题意:给定一些木棒(25w根),木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的。
用到的知识点:欧拉通路+并查集+trie树。
1. 首先我们可以分析问题,这是一个一笔画问题,就是询问是否存在欧拉通路。(不是欧拉回路)
2.由于颜色数可以多达25W,我们必须找一种数据结构来存储字符串,实现高效查找。我们就想到了trie树。
关于一个图存在欧拉通路:只需保证:(1)该图是连通图,(2)每个节点的度(入度+出度)是偶数(或有且仅有2个节点的度为奇数,这两个点是起点和终点)。
3.一个图是否是连通图,我们可以用并查集来判断。
下面我们就可以开始写代码了......
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define MAX 26
struct Node{
int isstr;//记录此处是否构成一个word。
int id;
Node *next[MAX];
Node(){
memset(next,0,sizeof(next));
isstr=0;
}
};
Node *root=new Node;
int nodesum=1;
//始终只返回某个字符串的ID
int Insert(char *s)
{
Node *p=root ,*q;
while(*s)
{
if(p->next[*s-'a']==NULL)
{
q=new Node;
p ->next[*s-'a'] = q;
}
p=p->next[*s-'a'];
s++;
}
if(p->isstr==0)
{
p->isstr=1;
p->id=nodesum++;
}
return p->id;
}
void myfree(Node *p){
for(int i = 0; i < MAX; i++){
if(p->next[i] != NULL){
myfree(p->next[i]);
}
}
delete p;
}
int degree[500002]={0};
int fat[500002];
int Find(int x)
{
if(fat[x]==x)
return x;
fat[x]=Find(fat[x]);
return fat[x];
}
int main()
{
//freopen("in.txt","r",stdin);
char s[11],e[11];
int ids,ide,x,y,i;
for(i=1;i<500002;i++)
fat[i]=i;
while(~scanf("%s%s",s,e))
{
ids=Insert(s);//得到该字符串的ID
ide=Insert(e);
degree[ids]++;
degree[ide]++;
x=Find(ids);
y=Find(ide);
fat[y]=x;//合并集合
}
//并查集检查该图是否连通
int flag=0;
for(i=1;i<nodesum;i++)
if(fat[i]==i)
{
flag++;
if(flag>1) break;
}
if(flag>1)
{
printf("Impossible\n");
return 0;
}
//end 检查该图是否连通
//下面检查每个节点的度
flag=0;
for(i=1;i<nodesum;i++)
if(degree[i]&1)
{
flag++;
if(flag>2) break;
}
if(flag==0||flag==2)
printf("Possible\n");
else
printf("Impossible\n");
//end检查每个节点的度
myfree(root);//释放字典树
return 0;
}