偶尔看到的这个题目。。实在是太屌了。。一道题包含三个内容。。
首先题意是 给出一堆木棍 每个木棍两段各有一种颜色。然后把这些木棍连成长木棍。然后 连接处必须颜色相等。
因为不是练成圈 所有是欧拉通路就行。
这个题目考查三个地方。第一个是欧拉通路 一个条件是 所有点的度数要么全是偶数 要么有两个是奇数
第二个地方是并查集 因为欧拉通路的 另一个条件是 这个图当然得是联通的。。判连通性直接并查集就行。因为这个只要判断联通性 所以可以路径压缩了。
第二点就是带路径压缩的并查集了 前几天刚敲过。。
第三个就是tire数 就是字典树。以前好像写过一次字典树 先写一个博文把那个回顾一下吧。是hdu1251
困了。。明儿再写吧。。
wa了一次ac了 wa是因为忘记把输出中间结果的那句printf注释掉了。。
我觉得这个题目的新亮点就是 那个findindex函数 用一个字符串做参数 然后在字典树里面找 如果找不到 就一直new Node(); 最后 这个Node的index=color++;
如果找到了直接就返回index 就是要找到这种颜色代表的节点的编号。
之后就简单点了 路径压缩的并查集查找 合并。
然后看fa数组 是不是有多于一个的-1 如果有 就说明这个图不连通 那么不满足欧拉通路的第一个条件
再看第二个条件 其实两个条件同时判断的 因为遍历一遍就行
degree数组取bool就行 每次取非 偶数次还是0 奇数次就是一了
1的个数大于二 就不行
最后看1的个数是不是1
一开始并查集没用路径压缩 1800+ms 加了路径压缩 1300+ms
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=250000*2+100;
struct Node
{
int index;
Node * child[26];
Node()
{
index=-1;
for(int i=0; i<26; ++i)
child[i]=NULL;
}
};
Node *root,*p;
int color;
bool degree[maxn];
int fa[maxn];
int findindex(char str[])
{
p=root;
int i,j,len=strlen(str);
for(i=0; i<len; ++i)
{
if(p->child[str[i]-'a']==NULL)
{
p->child[str[i]-'a']=new Node();
}
if(i==len-1)
{
if(p->child[str[i]-'a']->index==-1)
{
p->child[str[i]-'a']->index=color;
return color++;
}
else
return p->child[str[i]-'a']->index;
}
p=p->child[str[i]-'a'];
}
}
int findset(int x)
{
return (fa[x]==-1)? x : fa[x]=findset(fa[x]);
}
void Union(int x,int y)
{
int x1=findset(x);
int x2=findset(y);
if(x1!=x2)
fa[x1]=x2;
}
int main()
{
root =new Node();
color=0;
memset(degree,0,sizeof(degree));
memset(fa,-1,sizeof(fa));
char str1[15],str2[15];
while(scanf("%s %s",str1,str2)!=EOF)
{
int x1=findindex(str1);
int x2=findindex(str2);
degree[x1]=!degree[x1];
degree[x2]=!degree[x2];
Union(x1,x2);
}
int cnt=0,cnt2=0;
for(int i=0; i<color; ++i)
{
if(fa[i] == -1) cnt2++;
if(degree[i])
cnt++;
if(cnt>2 || cnt2>1)
{
printf("Impossible\n");
return 0;
}
}
if(cnt==1)
{
printf("Impossible\n");
return 0;
}
printf("Possible\n");
return 0;
}