题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19492
题意:给一些字符串,每个长度不超过1000,问能不能首尾相接成一个,相接部分字母相同
思路:本质就是问能不能把所有边都走一遍且仅走一次,可以抽象成有向图的欧拉回路问题。能够相接成一个的满足如下条件:首部出现的每种字母数,都等于尾部出现的对应的字母数,或者仅有两个不等于且满足一个为首部 - 1= 尾部另一个为首部 + 1 = 尾部,可以把每个字母抽象成一个点,首部看着入度,尾部看作出度,这就成了一个有向图,注意判断图的连通性,用并查集,不连通的必然不能相接成一个
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1010;
char s[N];
int par[N];
void init()
{
for(int i = 0; i < N; i++)
par[i] = i;
}
int ser(int x)
{
int r = x, i = x, j;
while(r != par[r]) r = par[r];
while(i != r) j = par[i], par[i] = r, i = j;
return r;
}
void unite(int x, int y)
{
x = ser(x), y =ser(y);
if(x == y) return;
par[x] = y;
}
int main()
{
int arr[50], brr[50];
int t, n;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
memset(arr, 0, sizeof arr);
memset(brr, 0, sizeof brr);
init();
for(int i = 0; i < n; i++)
{
scanf(" %s", s);
arr[s[0] - 'a']++;
int len = strlen(s);
brr[s[len-1] - 'a']++;
unite(s[0] - 'a', s[len-1] - 'a');
}
int cnt = 0;
for(int i = 0; i < 26; i++)
if((arr[i] || brr[i]) && par[i] == i)
cnt++;
if(cnt != 1)
{
printf("The door cannot be opened.\n");
continue;
}
bool flag = true;
int num1 = 0, num2 = 0;
for(int i = 0; i < 26; i++)
{
if(arr[i] != brr[i])
{
if(arr[i] + 1 == brr[i]) num1++;
else if(arr[i] - 1 == brr[i]) num2++;
else
{
flag = false;
break;
}
}
}
if(num1 + num2 > 2) flag = false;
if(flag) printf("Ordering is possible.\n");
else printf("The door cannot be opened.\n");
}
return 0;
}