题目链接:http://poj.org/problem?id=2513
题意:有n段木头,每段木头的两端都有颜色。相同颜色的木头能拼接在一起成为一段。问是否能把所有木头拼接在一起。成为一段。
题解:这道题,和刘汝佳的紫书上的一道题欧拉回路的题目很像,据说这道题map映射会超时,所以映射就用字典树来代替。那么这道题的思路就可以变成,每个木头分成两段,然后每个端点的颜色hash成一个点。连接之后判断欧拉回路。并用并查集判断连通性。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 5e5 + 5;
int pre[maxn];
int in[maxn];
int digit;
struct len{
int num;
int flag;
struct len *next[27];
len(){
flag = 0 ;
memset(next,0,sizeof(next));
}
}root;
int insert(char *s){
struct len *p = &root;
int length = strlen(s);
for(int i = 0 ; i < length ; i ++){
int index = s[i] -'a';
if(p->next[index] == NULL){
p->next[index] = new struct len;
}
p = p->next[index];
}
if(p->flag != 1){
p->flag = 1;
p->num = digit ++;
return p->num;
}
else return p->num;
}
int find(int x){
return pre[x] = (x == pre[x] ? x : find(pre[x]));
}
void add(int x,int y){
int fx = find(x);
int fy = find(y);
if(fx != fy){
pre[fx] = fy;
}
}
int main(){
for(int i = 1 ; i < maxn ; i ++)
pre[i] = i;
char s1[15],s2[15];
digit = 0;
memset(in,0,sizeof(in));
while(scanf("%s%s",s1,s2) != EOF){
int t1 = insert(s1),t2 = insert(s2);
add(t1,t2);
in[t1]++;
in[t2]++;
}
int end = find(0),number = 0;
if(in[0]%2) number++;
for(int i = 1; i < digit ; i ++){
if(find(i) != end){
printf("Impossible\n");
return 0;
}
if(in[i] % 2) number++;
}
if(number == 0 || number == 2)
printf("Possible\n");
else printf("Impossible\n");
}