题目连接:http://acm.nyist.net/JudgeOnline/problem.php?pid=230
大意:给出n个两端染色棍,端点颜色相同的棍可以拼接起来, 给你n个棍, 问能否拼接成一个棍, 可以输出“Possible” 否则输出“Impossible”。
PS: n为零,输出“Possible”;
读懂题意后就知道是欧拉道路题了, 用欧拉道路的定理有个前提是使这些棍都要能相连接,但是题没说满足条件,所以我们要判断是否都能连接,如果不能就直接输出“Impossible”;
判断能否连接我们可以用并查集快速求出;还有一个问题是给这些颜色编号,c++的容器里的map可以很好的解决, 但是这道题用了就超时了, 所以我们可以用字典树快速给颜色编号。
剩下的就套用无向图的欧拉道路的定理。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N = 26;
const int maxn = 500000 + 10;
struct Trie
{
int v;
Trie* next[N];
};
int F[maxn], sum[maxn], t;
Trie* root;
void inin(int n)
{
memset(sum, 0, sizeof(sum));//统计各个端点的度
t = 0;//颜色的编号
for(int i = 0; i <= n; i++)//初始化并查集
F[i] = i;
root = (Trie*) malloc (sizeof(Trie));//建字典树
root->v = 0;
for(int i = 0; i < N; i++)
root->next[i] = NULL;
}
int Find(int x)
{
if(x == F[x])
return x;
return F[x] = Find(F[x]);
}
int merge(char s[])
{
int len = strlen(s);
Trie *p, *q;
p = root;
bool flag;
for(int i = 0; i < len; i++)
{
flag = false;
int id = s[i] - 'a';
if(p->next[id] == NULL)
{
flag = true;
q = (Trie*) malloc (sizeof(Trie));
q->v = 0;
for(int i = 0; i < N; i++)
q->next[i] = NULL;
p->next[id] = q;
}
p = p->next[id];
}
if(flag)
{
p->v = ++t;
sum[t]++;
return p->v;
}
if(p->v == 0)// 这也是一种新的颜色 如:原来颜色为“abcdef”, 新的颜色为“abc”;
{
p->v = ++t;
sum[t]++;
return p->v;
}
if(p->v)
{
sum[p->v]++;
return p->v;
}
}
int main()
{
int T, n;
char sa[50], sb[50];
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
if(n == 0)
{
puts("Possible");
continue;
}
inin(n*2);
while(n--)
{
scanf("%s%s", sa, sb);
int p = merge(sa);
int q = merge(sb);
int x = Find(p);
int y = Find(q);
if(x != y)//合并集合
F[y] = x;
}
int c = 0, cc = 0;
for(int i = 1; i <= t; i++)
if(F[i] == i)
c++;
if(c > 1)
{
puts("Impossible");
continue;
}
for(int i = 1; i <= t; i++)
if(sum[i]%2)
cc++;
if(cc==0 || cc==2)
puts("Possible");
else
puts("Impossible");
}
return 0;
}