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;
}


原文地址:https://www.cnblogs.com/lvpengms/p/1662787.html