#include<iostream>#include<cstring>#include<cstdio>usingnamespace std;typedefunsignedint ui;//unsigned int防止出現爆int.constint N1 =4e6+10;
ui trie[N1][2], tot, flag[N1];voidbuild_trie(ui x){//建立字01字典樹的過程。int root =0;for(int i =31; i >=0; i--){題意不超過2^32,從32位開始,其實也可以30,但是不要超過31,如果用int.int u = x >> i &1;if(!trie[root][u]) trie[root][u]=++tot;root = trie[root][u];}flag[root]= x;//這個節點標記為這個數的值。}
ui find_max(ui x){//找到與之匹配的異化值最大的數。int root =0;for(int i =31; i >=0; i--){int u = x >> i &1;//取出這一位的二進制數。if(trie[root][!u])//優先進入與之不同的二進制數位。root = trie[root][!u];else root = trie[root][u];}return flag[root];//返回查找的最優答案。}intmain(){// freopen("D:\\Code\\ce.txt", "r", stdin);ui t, a, n, m;scanf("%u",&t);for(int k =1; k <= t; k++){printf("Case #%d:\n", k);tot =0;memset(trie,0,sizeof trie);//多組讀入,注意清零。scanf("%u %u",&n,&m);for(int i =0; i < n; i++){scanf("%u",&a);build_trie(a);}for(int i =0; i < m; i++){scanf("%u",&a);printf("%u\n",find_max(a));}}return0;}
hdu 1251鏈接
這題應該比上題還簡單,直接上代碼了。
#include<iostream>#include<cstring>#include<cstdio>usingnamespace std;constint N =3e6+10;int trie[N][26], flag[N], tot;char s[20];voidbuild_trie(){int root =0, n =strlen(s);for(int i =0; i < n; i++){int u = s[i]-'a';if(!trie[root][u]) trie[root][u]=++tot;root = trie[root][u];flag[root]++;//單詞經過的節點,加一。}}intfind_sum(){int root =0, n =strlen(s);for(int i =0; i < n; i++){int u = s[i]-'a';if(!trie[root][u])return0;//出現一個字母在字典中不匹配,立即返回查找不到。root = trie[root][u];}return flag[root];//返回這個節點有多少單詞經過}intmain(){// freopen("D:\\Code\\ce.txt", "r", stdin);while(gets(s)){if(s[0]==0)break;build_trie();}while(gets(s))printf("%d\n",find_sum());return0;}
hdu 1247鏈接
這題應該是比上兩題更難一點,具體看代碼詳解吧。
#include<iostream>#include<cstdio>#include<cstring>usingnamespace std;constint N1 =5e6+10, N2 =5e4+10;int trie[N1][26], is_word[N1], tot;
string str[N2];voidbuild_trie(string s){//建字典樹。int root =0, n = s.size();for(int i =0; i < n; i++){int u = s[i]-'a';if(!trie[root][u]) trie[root][u]=++tot;root = trie[root][u];}is_word[root]=1;//標記這個節點有單詞。}booljudge_tail(string s,int pos){//判斷后綴是否是一個單詞,pos是后綴的起始位置。int root =0, n = s.size();for(int i = pos; i < n; i++){int u = s[i]-'a';if(!trie[root][u])returnfalse;root = trie[root][u];if(is_word[root]&& i == n -1)//整個需要判斷的后綴是否是一個單詞。returntrue;}returnfalse;}booljudge_front(string s){//這里判斷單詞的前綴是否是一個單詞。int root =0, n = s.size();for(int i =0; i < n; i++){int u = s[i]-'a';if(!trie[root][u])returnfalse;//有一個字母沒有查找到,返回失敗。root = trie[root][u];if(is_word[root]&&judge_tail(s, i +1))//前綴是一個單詞,接下來就是判斷后綴是否是一個單詞。returntrue;}returnfalse;}intmain(){// freopen("D:\\Code\\ce.txt", "r", stdin);int n =0;while(cin >> str[n])build_trie(str[n++]);for(int i =0; i < n; i++)if(judge_front(str[i]))cout << str[i]<< endl;return0;}
Poj 3764鏈接
這題應該是這幾題里面最難的題了,但是卻又跟第一題有點類似。
#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>usingnamespace std;constint N1 =2e5+10, N2 =4e6+10;int trie[N2][2], tot, cnt, n, head[N1], a[N1];struct Edge {//鏈式向前星。int to, next, value;}edge[N1];voidadd(int x,int y,int value){//存圖的過程edge[cnt].to = y;edge[cnt].value = value;edge[cnt].next = head[x];head[x]= cnt++;}voiddfs(int u,int fa,int sum){//通過dfs得到每個節點到根節點的異或值。a[u]= sum;for(int i = head[u]; i; i = edge[i].next){if(edge[i].to != fa)dfs(edge[i].to, u, sum ^ edge[i].value);}}voidbuild_trie(int x){//建立字典樹。int root =0;for(int i =30; i >=0; i--){int u = x >> i &1;if(!trie[root][u]) trie[root][u]=++tot;root = trie[root][u];}}intfind_max(int x){//查找最大值。int root =0, ans =0;for(int i =30; i >=0; i--){int u = x >> i &1;if(trie[root][!u]){ans +=(1<< i);//如果走這里的話,我們可以得到答案的這一位是1,或者我們可以像第一題一樣現在建立字典樹的時候記錄下節點的值然后在返回這個最大值,最后再和當前查找的異或。root = trie[root][!u];}else root = trie[root][u];}return ans;}intmain(){while(scanf("%d",&n)!=EOF){tot =0, cnt =1;memset(trie,0,sizeof trie);memset(head,0,sizeof head);//多組輸入, 清零。for(int i =1; i < n; i++){int x, y, v;scanf("%d %d %d",&x,&y,&v);add(x, y, v);add(y, x, v);}dfs(0,0,0);for(int i =0; i < n; i++)//得到異或值后,開始建字典樹。build_trie(a[i]);int ans =0;for(int i =0; i < n; i++)ans =max(ans,find_max(a[i]));printf("%d\n", ans);}return0;}