poj 2513 Colored Sticks

/*
题意: 有一些木棍,每根木棍两端都有颜色,颜色为小于10的字符串,
问能否将所有的木棍排成一排,使得每两根木棍衔接的地方颜色相同

思路: 将所有的颜色看做节点,每根木棍连接两种颜色,可以看作两颜色节点之间的连边,构成一幅图,
问题转化成每条边都走一次,即遍历所有木棍,也就是判断 无 向 图 中是否存在 欧 拉 道 路

对于欧拉图的判断,有两个,首先判断连通性,在图连通的前提下再判断各节点的度数,
有两个奇节点或者全为偶节点才存在 欧 拉 道 路
可以用并查集判断连通性,而因为节点是字符串,所以还需要对字符串哈希,也可以用trie树来给字符串赋编号

*/

#include <iostream> // 欧拉道路 + trie树
#include <string>
using namespace std;
#define maxn 500002
struct Node //trie字典树用来给字符串赋编号,也就是哈希
{
int next[26];
int pos; //记录该节点代表的字符串在表中出现的位置,若pos=-1则说明还未出现过该字符串
}table[2500000];
int cur,rear; //rear表示节点在表中的下标的末尾
int num[maxn]; //num记录节点度数
int p[maxn],hei[maxn];
void init()
{
memset(table[0].next,-1,sizeof(table[0].next));
for(int i=1;i<maxn;++i)
{
p[i]=i;
hei[i]=0;
num[i]=0;
}
cur=1;
rear=0; //节点下标从 0 开始
}
int insert(char ch[]) //返回字符串ch在表中的位置
{
Node* p=&table[0]; //table[0]作为根节点
for(int i=0;ch[i];++i)
{
int j=ch[i]-'a';
if(p->next[j]==-1)
{
p->next[j]=cur++;
Node* q=&table[p->next[j]];
for(int k=0;k<26;++k)
q->next[k]=-1;
q->pos=-1; //表示还没出现过该字符串(路径从根节点到q节点)
}
p=&table[p->next[j]];
}
if(p->pos==-1)
{
p->pos=rear++; //把新出现的字符串插入到位置rear上
}
return p->pos;
}
int find(int x)
{
return p[x]==x ? x : p[x]=find(p[x]);
}
void Union(int a,int b)
{
int x=find(a),y=find(b);
if(x==y)
return ;
if(hei[x]>hei[y])
p[y]=x;
else
p[x]=b;
if(hei[x]==hei[y])
hei[y]++;
}
int main()
{
char s1[12],s2[12];
int suc=1;
init();
while(scanf("%s%s",s1,s2)!=EOF)
{
if(!suc)
continue;
int x=insert(s1);
int y=insert(s2);
num[x]++;
num[y]++;
Union(x,y);
}
int t=find(0);
for(int i=1;i<rear;++i)
{
if(find(i)!=t) //说明不连通
{
suc=0;
break;
}
}
if(suc)
{
int odd=0;
for(int i=0;i<rear;++i)
{
if(num[i]%2==1)
{
odd++;
if(odd>2) //一个连通的无向图存在欧拉道路最多只能有两个度数为奇数的节点
{
suc=0;
break;
}
}
}
}
if(suc)
printf("Possible\n");
else
printf("Impossible\n");
return 0;
}

posted on 2012-03-28 16:36  sysu_mjc  阅读(363)  评论(0编辑  收藏  举报

导航