给你250000个棒子,棒子两头有颜色,问你可不可以用完所有的棒子,把棒子连起来,并且使得棒子相连的两头颜色一样。
其实就是求欧拉回路。
有无向图存在欧拉路的充要条件为:
1->图是连通的;
2->所有节点的度为偶数,或者有且只有两个度为奇数的节点。
判断图的连通性,用并查集搞定。又题目给的棒子颜色是字符串,所以要用trie树把每个颜色的编号记录下来。
注意,这里用map会超时。。因为map基于hash,并不高效,所以这里需要用trie树来处理。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define MAX 260000
int uset[MAX],degree[26000];
int BCG_root(int k)
{
if(k==uset[k])return k;
return uset[k]=BCG_root(uset[k]);
}
int BCG_init()
{
for(int i=0;i<MAX;++i)
uset[i]=i;
return 0;
}
struct node
{
int flag; //如果是终止状态,则标记是哪个字符
int tag;
int next[26];
int init()
{
memset(next,-1,sizeof(next));
flag=0;
tag=0;
return 0;
}
}trie[260000];
int size=1;
const int root=0;
int val(char a)
{
return a-'a';
}
int insert(char* s,int k)
{
int p=root;
for(int i=0;s[i];++i)
{
int v=val(s[i]);
if(trie[p].next[v]==-1)
{
trie[p].next[v]=size;
trie[size].init();
++size;
}
p=trie[p].next[v];
}
trie[p].tag=1;
trie[p].flag=k;
return 0;
}
int match(char* s)
{
int p=root;
for(int i=0;s[i];++i)
{
int v=val(s[i]);
p=trie[p].next[v];
if(trie[p].tag)
return trie[p].flag;
}
return 0;
}
void init()
{
size=1;
trie[root].init();
return ;
}
int main()
{
char str[15];
int n,cnt,i,j,anc,sum,t1,t2;
init();
BCG_init();
cnt=1;
memset(degree,0,sizeof(degree));
while (scanf("%s",str) != EOF)
// for (int k=0; k<5; k++)
{
// scanf("%s",str);
j=match(str);
if (j == 0)
{
insert(str,cnt);
degree[cnt]++;
t1=cnt;
cnt++;
}
else
{
degree[j]++;
t1=j;
}
scanf("%s",str);
j=match(str);
if (j == 0)
{
insert(str,cnt);
degree[cnt]++;
t2=cnt;
cnt++;
}
else
{
degree[j]++;
t2=j;
}
uset[BCG_root(t1)]=BCG_root(t2);
}
anc=BCG_root(1);
sum=0;
// printf("anc=%d\n",anc);
for (i=1; i<cnt; i++)
{
// printf("%d\n",i);
// printf("%d\n",BCG_root(i));
// printf("!!\n");
if (BCG_root(i) != anc)
{
// printf("@");
break;
}
if (degree[i]%2 == 1)
sum++;
}
if (i != cnt || (sum != 2 && sum != 0))
printf("Impossible\n");
else
printf("Possible\n");
}