poj2513 Colored Sticks【欧拉迹+并查集+字典树】
样例是这样的:
Sample Input
blue red red violet cyan blue blue magenta magenta cyan
Sample Output
Possible
把棍子看做无向边,把端点看做点,且颜色相同的端点视作同一点。
画成图后,是这个样子:
题目的问题是,是否能把这些棍子排成一条直线,且连接处颜色相同。
如图,(v,e1,r,e2,b,e3,c,e4,m,e5,b)即为一种可行解。
这样点边交替的序列,包含了图中的每一条边,且每条边只走过一次。
这样的序列就是一条欧拉迹。
(欧拉迹包括欧拉环游和欧拉通路,欧拉环游的起点和终点相同,而欧拉通路则不同。
含有欧拉环游的图称为欧拉图。含有欧拉通路的图称为半欧拉图。)
事实上,问题的一种可行解与图中的一条欧拉迹相对应,而是否有解就是问是否存在欧拉迹。
View Code
1 #include<cstdio> 2 #include<cstring> 3 const int maxnode = 2500005; 4 const int MAXN = 500005; 5 6 int tree[MAXN],degree[MAXN],cnt; 7 struct Trie 8 { 9 int tree[maxnode][26],sz; 10 int id[maxnode]; 11 Trie() 12 { 13 sz=cnt=0; 14 memset(tree[0],0,sizeof(tree[0])); 15 memset(id,0,sizeof(id)); 16 } 17 int insert_search(char* ch) 18 { 19 int p=0; 20 for(int i=0;ch[i];i++) 21 { 22 int x=ch[i]-'a'; 23 if( !tree[p][x] ) 24 { 25 tree[p][x]=++sz; 26 memset(tree[sz],0,sizeof(tree[sz])); 27 } 28 p=tree[p][x]; 29 } 30 if( id[p] ) return id[p]; 31 return id[p]=++cnt; 32 } 33 }T; 34 35 int find(int x) 36 { 37 if( -1==tree[x] ) return x; 38 return tree[x]=find(tree[x]); 39 } 40 41 void merge(int x,int y) 42 { 43 int p1=find(x),p2=find(y); 44 if( p1!=p2 ) tree[p2]=p1; 45 } 46 47 int main() 48 { 49 char a[15],b[15]; 50 int u,v,s=0,j=0; 51 52 memset(tree,-1,sizeof(tree)); 53 memset(degree,0,sizeof(degree)); 54 while( ~scanf("%s%s",a,b) ) 55 { 56 u=T.insert_search(a); 57 v=T.insert_search(b); 58 degree[u]++; 59 degree[v]++; 60 merge(u,v); 61 } 62 for(int i=1;i<=cnt;i++) 63 { 64 s+=(tree[i]==-1); 65 j+=(degree[i]&1); 66 } 67 if( 0==cnt || (1==s && ( !j || 2==j ) ) ) puts("Possible"); 68 else puts("Impossible"); 69 return 0; 70 } 71 /* 72 关键在于:把问题转换成图中是否存在欧拉迹。 73 并查集判断连通性。 74 字典树给串编号 75 再加个判断是否存在欧拉迹 76 */