BZOJ 4337 树的同构
很明显,这应该是一道模版题(因为我很快就在一本书上找到了这道题的模版),不过令我比较奇怪的大概是有根树和无根树的概念,以及在这道题目中根有卵用吗? (看来树这一块的知识还是要补一下)。 树的同构很明显应该是用hash来判断的,当然了,不同的人设计的hash函数不同了。这道题正确的应该是要在树的重心上面跑这道题的模版,(如果你要问我树的重心是啥,我只能跟你说,如果我知道的话,下面这份代码就不会把几乎所有的点都跑一次了,但是由于N<=50,M <= 50 很明显这样跑完还是很快的,事实证明也只跑了32毫秒,但本着求真务实的心态,找个时间再补下树吧!)。很明显,尽管两棵树的形态完全相同,但如果从不同的节点开始跑这个模版,所得的hash值也会不同。所以正确的是要在几乎唯一的重心上跑(据说,一棵有根树的重心最多有两个)。加油吧!相信自己。(我是一条可耻的源程狗)。
1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 #include<set> 5 #include<map> 6 #include<algorithm> 7 #define ull unsigned long long 8 #define magic 107ull 9 #define rep(i,j,k) for(int i = j; i <= k; i++) 10 #define maxn 60 11 using namespace std; 12 13 int read() 14 { 15 int s = 0, t = 1; char c = getchar(); 16 while( !isdigit(c) ){ 17 if( c == '-' ) t = -1; c = getchar(); 18 } 19 while( isdigit(c) ){ 20 s = s * 10 + c -'0'; c = getchar(); 21 } 22 return s * t; 23 } 24 25 ull pow(ull key,int n) 26 { 27 ull ret = 1ull; 28 while( n ){ 29 if( n & 1 ){ 30 ret *= key; 31 } 32 key *= key, n >>= 1; 33 } 34 return ret; 35 } 36 37 struct hash{ 38 int length; ull key; 39 40 hash(): length(0), key(0) {} 41 hash(char c): length(1), key(c) {} 42 hash(int l,ull key): length(l), key(key) {} 43 }; 44 vector<hash> childs[maxn]; 45 46 bool operator < (const hash&a, const hash&b){ 47 return a.key < b.key; 48 } 49 50 hash operator + (const hash&a, const hash& b){ 51 return hash(a.length+b.length,a.key*pow(magic,b.length)+b.key); 52 } 53 54 void operator += (hash&a,const hash&b){ 55 a = a + b; 56 } 57 58 vector<int> g[maxn]; 59 60 hash dfs(int pre,int now) 61 { 62 hash ret; 63 childs[now].clear(); int s = g[now].size(); 64 rep(i,0,s-1){ 65 int to = g[now][i]; 66 if( to == pre ) continue; 67 childs[now].push_back(dfs(now,to)); 68 } 69 sort(childs[now].begin(),childs[now].end()); 70 for(vector<hash>::iterator iter = childs[now].begin(); iter != childs[now].end(); iter++){ 71 ret += *iter; 72 } 73 ret = '(' + ret + ')'; 74 return ret; 75 76 } 77 78 ull gethash(int root) 79 { 80 return dfs(-1,root).key; 81 } 82 83 set<ull> s; 84 map<ull,int> mp; 85 86 void clear() 87 { 88 rep(i,1,maxn) g[i].clear(); 89 } 90 91 int main() 92 { 93 int n = read(); 94 rep(i,1,n){ 95 clear(); s.clear(); 96 int m = read(); 97 rep(j,1,m){ 98 int x = read(); 99 if( x ) g[j].push_back(x), g[x].push_back(j); 100 } 101 bool ok = 0; 102 rep(j,1,m){ 103 ull key = gethash(j); 104 if( mp[key] ) { 105 printf("%d\n", mp[key]); 106 ok = 1; 107 break; 108 } 109 else s.insert(key); 110 } 111 if( !ok ){ 112 printf("%d\n", i); 113 for(set<ull>::iterator iter = s.begin(); iter != s.end(); iter++ ){ 114 mp[*iter] = i; 115 } 116 } 117 } 118 return 0; 119 }
好了,这是加了找重心优化的树的同构(思想很简单,就是让所有的一个或两个重心去跑,然后取最大的,就这样)(20毫秒) 加油,多学多练。
1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 #include<map> 5 #include<algorithm> 6 #define ull unsigned long long 7 #define magic 107ull 8 #define rep(i,j,k) for(int i = j; i <= k; i++) 9 #define maxn 60 10 using namespace std; 11 12 int read() 13 { 14 int s = 0, t = 1; char c = getchar(); 15 while( !isdigit(c) ){ 16 if( c == '-' ) t = -1; c = getchar(); 17 } 18 while( isdigit(c) ){ 19 s = s * 10 + c -'0'; c = getchar(); 20 } 21 return s * t; 22 } 23 24 ull pow(ull key,int n) 25 { 26 ull ret = 1ull; 27 while( n ){ 28 if( n & 1 ){ 29 ret *= key; 30 } 31 key *= key, n >>= 1; 32 } 33 return ret; 34 } 35 36 struct hash{ 37 int length; ull key; 38 39 hash(): length(0), key(0) {} 40 hash(char c): length(1), key(c) {} 41 hash(int l,ull key): length(l), key(key) {} 42 }; 43 vector<hash> childs[maxn]; 44 45 bool operator < (const hash&a, const hash&b){ 46 return a.key < b.key; 47 } 48 49 hash operator + (const hash&a, const hash& b){ 50 return hash(a.length+b.length,a.key*pow(magic,b.length)+b.key); 51 } 52 53 void operator += (hash&a,const hash&b){ 54 a = a + b; 55 } 56 57 vector<int> g[maxn]; 58 59 hash dfs(int pre,int now) 60 { 61 hash ret; 62 childs[now].clear(); int s = g[now].size(); 63 rep(i,0,s-1){ 64 int to = g[now][i]; 65 if( to == pre ) continue; 66 childs[now].push_back(dfs(now,to)); 67 } 68 sort(childs[now].begin(),childs[now].end()); 69 for(vector<hash>::iterator iter = childs[now].begin(); iter != childs[now].end(); iter++){ 70 ret += *iter; 71 } 72 ret = '(' + ret + ')'; 73 return ret; 74 75 } 76 77 ull gethash(int root) 78 { 79 return dfs(-1,root).key; 80 } 81 82 map<ull,int> mp; 83 84 void clear() 85 { 86 rep(i,1,maxn) g[i].clear(); 87 } 88 89 int son[maxn], f[maxn], m, mx; 90 void find_root(int pre,int now) 91 { 92 son[now] = 1, f[now] = 0; int s = g[now].size(); 93 rep(i,0,s-1){ 94 int to = g[now][i]; 95 if( to != pre ){ 96 find_root(now,to); 97 son[now] += son[to]; 98 if( son[to] > f[now] ) f[now] = son[to]; 99 } 100 } 101 if( m - son[now] > f[now] ) f[now] = m - son[now]; 102 if( f[now] < mx ) mx = f[now]; 103 } 104 105 int main() 106 { 107 int n = read(); 108 rep(i,1,n){ 109 clear(); 110 m = read(); mx = 0x7ffffff; 111 rep(j,1,m){ 112 int x = read(); 113 if( x ) g[j].push_back(x), g[x].push_back(j); 114 } 115 find_root(0,1); ull key = 0; 116 rep(j,1,m){ 117 if( f[j] == mx ) { 118 ull value = gethash(j); 119 if( value > key ) key = value; 120 } 121 } 122 if( mp[key] ) printf("%d\n", mp[key]); 123 else { 124 printf("%d\n", i); 125 mp[key] = i; 126 } 127 } 128 return 0; 129 }
————————————————