POJ 2513 Colored Sticks
/* 此题考察 并查集 和 hash (或trie树)应用,我是用的hash,可以证明:如果满足题意要求,那么同种颜色出现次数为奇数次的个数不超过2,即最多有两种颜色他们出现的次数为奇数,并且所有的颜色属于同一集,根据这个原理,便有了hash+并查集的算法。这样不怎么费时,510ms就过了。
在并查集 中,最父节点的值为负值,其绝对值是整个子树节点的个数
*/
#include<iostream>
using namespace std;
int color[500002],set[500002];
int Hash(char * str)
{
int hash = 1;
while(*str)
hash = (hash*29 + *str++ - 'a')%9991;
return hash;
}
int find_set(int x)
{
int tmp=0;
int root=x;
while(set[root]>=0)
{
root=set[root];
}
while(x!=root)
{
tmp=set[x];
set[x]=root;
x=tmp;
}
return root;
}
void union_set(int root1,int root2)
{
int sum = set[root1]+set[root2];
if(set[root1]>set[root2])
{
set[root1] = root2;
set[root2] = sum;
}
else
{
set[root2] = root1;
set[root1] = sum;
}
}
int main()
{
int n1,n2,n=0,root1,root2,i,no=0;
char a[11],b[11];
for(i=0;i<500002;++i)
{
set[i]=-1;
color[i]=0;
}
while(scanf("%s%s",a,b)!=EOF)
{
++n;
n1=Hash(a);
n2=Hash(b);
++color[n1];
++color[n2];
root1=find_set(n1);
root2=find_set(n2);
if(root1!=root2)
union_set(root1,root2);
}
int root=1;
for(int i=0;i<500002;++i)
{
if(color[i]>0)
{
if(color[i]%2)
{
++no;
if(no>2)
{
printf("Impossible\n");
return 0;
}
}
if(root==1)
root = find_set(i);
else
if(root!=find_set(i)){ printf ("Impossible\n");return 0;}
}
}
printf("Possible\n");
return 0;
}
using namespace std;
int color[500002],set[500002];
int Hash(char * str)
{
int hash = 1;
while(*str)
hash = (hash*29 + *str++ - 'a')%9991;
return hash;
}
int find_set(int x)
{
int tmp=0;
int root=x;
while(set[root]>=0)
{
root=set[root];
}
while(x!=root)
{
tmp=set[x];
set[x]=root;
x=tmp;
}
return root;
}
void union_set(int root1,int root2)
{
int sum = set[root1]+set[root2];
if(set[root1]>set[root2])
{
set[root1] = root2;
set[root2] = sum;
}
else
{
set[root2] = root1;
set[root1] = sum;
}
}
int main()
{
int n1,n2,n=0,root1,root2,i,no=0;
char a[11],b[11];
for(i=0;i<500002;++i)
{
set[i]=-1;
color[i]=0;
}
while(scanf("%s%s",a,b)!=EOF)
{
++n;
n1=Hash(a);
n2=Hash(b);
++color[n1];
++color[n2];
root1=find_set(n1);
root2=find_set(n2);
if(root1!=root2)
union_set(root1,root2);
}
int root=1;
for(int i=0;i<500002;++i)
{
if(color[i]>0)
{
if(color[i]%2)
{
++no;
if(no>2)
{
printf("Impossible\n");
return 0;
}
}
if(root==1)
root = find_set(i);
else
if(root!=find_set(i)){ printf ("Impossible\n");return 0;}
}
}
printf("Possible\n");
return 0;
}