题意:每一个单词的长度最小2,最大1000,单词开头的字母和另外一个单词的末尾一样就可以连接起来,解所有的单词是不是都可以连接起来,没有遗漏的
把每一个单词的第一个字母当成一个结点,最后一个单词也作为一个结点,表示第一个字母有一条路径走到最后一个单词,题目的意思就转化为,单词开头字母和结尾
字母组成的图是不是一个联通图,并且这个图存在欧拉通路.
欧拉通路判定(不一定是成环),图中只有俩个结点的度是奇数,终点的入度比出度大1,起点的出度比入度大1,其他点的入度必须等于出度.
欧拉通路的判断+起点和终点的出度等于入度那就是欧拉回路了,但是这个题只要判断通路.
使用了并查集判断图是否联通.
AC时间:30ms
#include <iostream>
#include<stdio.h>
#include<math.h>
#include<memory.h>
using namespace std; int const max = 'z';
int const min = 'a';
int const length = 'z' - 'a' + 1;
void _init(int *a, int length);
int find(int key, int *a);
void join(int k1, int k2, int *a); int main()
{
freopen("d:\\1.txt", "r", stdin);
int c;
cin >> c;
string yes = "Ordering is possible.";
string no = "The door cannot be opened.";
while (c--)
{
int n;
cin >> n;
string str;
if (n == 1)
{
cin >> str;
cout << yes << endl;
continue;
}
int set[length];
int duIn[length];
int duOut[length];
int vis[length];
memset(vis, 0, sizeof(vis));
memset(duIn, 0, sizeof(duIn));
memset(duOut, 0, sizeof(duIn));
_init(set, length);
while (n--)
{
cin >> str;
int s, e;
s = str[0];
s -= 'a';
e = str[str.length() - 1];
e -= 'a';
duOut[s]++;
duIn[e]++;
vis[s] = 1;
vis[e] = 1;
join(s, e, set);
}
//判断度和根结点
int p = -1;
int s = 0;
int ok = 1;
for (int i = 0; i < length; i++)
{
if (!vis[i])
continue;
int key = find(i, set);
if (p == -1)
{
p = key;
}
else if (key != p)
{
ok = 0;
break;
}
if (duIn[i] != duOut[i])
{
int t = duIn[i] - duOut[i];
if ((t == -1 || t == 1) && (s <= 1))
{
t++;
}
else
{
ok=0;
break;
}
}
}
if (ok)
cout << yes << endl;
else
cout << no << endl; }
return 0;
} void join(int k1, int k2, int* a)
{
int p1 = find(k1, a);
int p2 = find(k2, a);
if (p1 != p2)
a[p1] = p2;
} int find(int key, int *a)
{
return key == a[key] ? key : a[key] = find(a[key], a);
} void _init(int* a, int length)
{
for (int i = 0; i < length; i++)
a[i] = i;
}