题意:
给一堆棍子,棍子由头尾两个字符串组成,棍子两两相连的条件是相接的部分字符串必须相同,问能否将这些棍子组成一条直线.
解题过程:
这题其实并不需要用字典树处理,用排序统计度数一样.
一开始我想到保证度数为奇数的点的数量小于2就行了,但这样明显不可以,点数为1时就不正确.
另外最重要的一点,当度数为奇数的点数量为0或2时,可以保证每条边都会被遍历且只有一次,但是,这样的图有可能是多个欧拉分路组成的非连通图.所以仍然不能满足题目要求.
然后我改用并查集判断是否连通,提交仍然WA,去网上看了下别人的做法,除了用字典树统计度数其它没有差别,直到我看到kuangbin大神的博客里写着要考虑没有棍子的情况.....晕.
正确思路:
题目等价与判断图是否是欧拉图
判断欧拉图条件
1.图连通
2.度数为奇数的点的个数为0或奇数.
条件一用并查集判断是否满足即可
条件二用字典树或排序都可以统计判断是否满足.
注意棍子为0的数据,答案应该是可以.
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
int f[501234];
struct p
{
char a[15];
int v; // 对点编号.
}b[501234];
int cmp(p a, p b )
{
return strcmp(a.a,b.a)<0;
}
int getf(int x)
{
if(x==f[x])return x;
else return f[x]=getf(f[x]);
}
void merg(int x, int y)
{
x=getf(x);
y=getf(y);
if(x!=y)
{
f[y]=x;
}
}
int main()
{
int i=0;
i=0;
while(~scanf("%s", b[i].a))
{
b[i].v=i/2;
i++;
b[i].v=i/2;
scanf("%s", b[i++].a);
}
sort(b, b+i, cmp);
int n;
n=i;
for(i=0; i<n/2; i++)f[i]=i;
int sum=1; //相同字符串个数,即点的度数.
int tosum=0; //度数为奇数点的个数
<pre name="code" class="cpp"> for(i=0; i<n-1; i++)
{
if(strcmp(b[i].a, b[i+1].a)==0)
{
sum++;
merg(b[i].v, b[i+1].v);
}
else
{
if(sum%2)tosum++;
sum=1;
}
}
if(sum%2)tosum++; //最后判断下最后一个点的度数是否是奇数.
for(i=0; i<n/2-1; i++)
{
if(getf(i)!=getf(i+1))break;
}
if((tosum==0 || tosum==2) && i==n/2-1) printf("Possible\n");
else if(n==0)printf("Possible\n"); //棍子为0的情况
else printf("Impossible\n");
return 0;
}