您的位置:首页 > 其它

poj 2513 Colored Sticks (欧拉回路+并查集+Hash)

2013-03-14 15:59 495 查看
题目链接:http://poj.org/problem?id=2513

题目大意: 给出无数根筷子,每个筷子头尾各一个单词代表颜色

颜色相同则可以拼在一起

如 blue red 的筷子和 red violet 的筷子可以拼在一起

如 red blue 的筷子和 red violet 的筷子也可以拼在一起

筷子不分头尾,可以任意调换

问所有的筷子能否拼成一条线?

解题思路: 把每个单词看成一个点,每根筷子就代表一条边!

这样就能得到一个图

所有筷子连成一条线,换句话说就是一次遍历所有的边

然后可以转化成"一笔连成"的问题,无向图的欧拉通路!

奇数度顶点的数量0或2时,欧拉通路成立

先判断这个图是不是连通图(并集合)

边数太多,输入的时候如果用strcmp判断是哪个点会TLE

我们可以用Hash来处理

代码:

//BKDRHash + 欧拉回路 + 并查集
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 251000
int parent[MAX]={0},v[MAX]={0};
unsigned int BKDRHash(char *str)
{
unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
unsigned int hash = 0;

while (*str)
{
hash = hash * seed + (*str++);
}

return (hash & 0x7FFFFFFF)%MAX;
}

void Empty() //初始化parent[]
{
int i;
for(i=0;i<MAX;i++)
parent[i]=i;
}

int Find(int x)  //并查集 Find()
{
int s,j;
s=x;
while(x!=parent[x])
{
x=parent[x];
}
while(s!=x)
{
j=parent[s];
parent[s]=x;
s=j;
}
return x;
}

void Union(int r1,int r2)   //并查集 Union()
{
int R1,R2;
R1=Find(r1);
R2=Find(r2);
if(R1!=R2)
{
parent[R1]=R2;
}
}

int main()
{
char a[11],b[11];
int i,pd,js,atemp,btemp,tempx;
Empty();  //别忘记初始化了!
while(scanf("%s%s",a,b)!=EOF)
{
atemp=BKDRHash(a);   //返回 哈希值
btemp=BKDRHash(b);   //返回 哈希值
v[atemp]++;      //顶点的度++
v[btemp]++;      //顶点的度++
if(Find(atemp)!=Find(btemp))
{
Union(atemp,btemp);
}

}
for(i=0,js=0;i<MAX;i++)
{
if(v[i]>0&&v[i]%2!=0)
js++;    //顶点的度为奇数的数目
}
if(js!=0&&js!=2)
{
printf("Impossible\n");
return 0;
}
for(i=0,tempx=-1,pd=1;i<MAX;i++)
{
if(v[i]>0)
{
if(tempx==-1)
{
tempx=Find(i);   //**寻找祖先,是Find()
}
else if(tempx!=Find(i))   //**祖先不同 就不符合,不是连通图
{
pd=0;
printf("Impossible\n");
return 0;
}
}
}
printf("Possible\n");
return 0;
}
注:原创文章,转载请注明出处
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: