题意大概是,让你每次输入两个颜色单词,表示这是连成一条木棍的单词(从这可以看出这是一个无向图,因为无前后关系),然后他要求说能否根据这个拼接成一条路线,把所有的木棍都应连接,把木棍看成边,单词看成点,就是要让你把所有的边都连一遍,当然是不重复也不漏的,这恰好是无向图欧拉通路的问题。因此要保证图是连通的,而且奇数点的个数要么是0要么是2.
这里判断图的连通用并查集(压缩路径),即看看最后是不是在同一个集合里面,而每个点的度的问题比较简单,难点在于如何表示这个点的状态,这里我们用字典树,然后用全局变量color记录当前已经出现的颜色的个数,返回这个数字表示这个状态(单词)。
这里用字典树的好处在哪?这里相当于用内存换时间的方法。所以搜索只要O(1)时间。假如不用字典树的话,那你每次都要遍历所有的单词。
#include<cstdio>
#include<iostream>
#include<string.h>
using namespace std;
#define MAXN 500010
struct trieTreeNode{
int id;
struct trieTreeNode* next[27];
bool flag;
trieTreeNode()
{
flag=false;
id=0;
memset(next,0,sizeof(next));
}
}root;
int color=0;
int p[MAXN],degree[MAXN];
int find(int x)
{
if(p[x]!=x)
p[x]=find(p[x]);
return p[x];
}
void Union(int a,int b)
{
int x1=find(a);
int x2=find(b);
if(x1!=x2)
p[x1]=x2;
return ;
}
int hash(char *str)
{
struct trieTreeNode* ptr=&root;
int len=0;
while(str[len]!='\0'){
int index=str[len++]-'a';
if(!ptr->next[index]){
ptr->next[index]= new trieTreeNode;
}
ptr=ptr->next[index];
}
if(ptr->flag==1){
return ptr->id;
}
else{
ptr->flag=true;
ptr->id=color++;
return ptr->id;
}
}
int main()
{
//initial
for(int i=0;i<MAXN;i++)
{
p[i]=i;
degree[i]=0;
}
char str1[11],str2[11];
int count=0;
while(cin>>str1>>str2){
int a,b;
a=hash(str1);
b=hash(str2);
degree[a]++;degree[b]++;
Union(a,b);
}
int s=find(0),num=0,yes=1;//num统计奇数节点的个数
for(int i=0;i<color;i++)
{
if(degree[i]%2==1)num++;
if(find(i)!=s)yes=0;
}
if(num!=0 && num!=2)yes=0;
if(yes)cout<<"Possible"<<endl;
else cout<<"Impossible"<<endl;
return 0;
}