类型:欧拉回路
题目:http://poj.org/problem?id=1386
思路:首先考虑的是将单词看做点,可以连接的单词之间连一条边,这样就是求一条路径包含所有的点,该问题为复杂的哈密尔顿问题。
然后考虑转化模型,将单词看做边,每个单词的首尾字符看做点,那么每个单词就是一条由首字符点连向尾字符点的边,即转化为就一条路径连接所有的边
,即欧拉路径[回路]问题。当只有一个点的入度等于初度 + 1,一个点的初度等于入度 + 1,其他点的入度 = 初度,或者所有点入度 = 初度时,结果为真。
!!!需要用并查集判断图的连通性。
// poj 1386 play on words
// wa wa 125MS 264K
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
using namespace std;
#define FOR(i,a,b) for(i = (a); i < (b); ++i)
#define FORE(i,a,b) for(i = (a); i <= (b); ++i)
#define FORD(i,a,b) for(i = (a); i > (b); --i)
#define FORDE(i,a,b) for(i = (a); i >= (b); --i)
#define max(a,b) ((a) > (b)) ? (a) : (b)
#define min(a,b) ((a) < (b)) ? (a) : (b)
#define CLR(a,b) memset(a,b,sizeof(a))
const int MAXN = 1010;
int n, t;
int ru[30], chu[30], p[30];
char ch[MAXN];
void makeSet() {
for(int i = 0; i <= 29; ++i)
p[i] = i;
}
int findSet(int u) {
return (u != p[u]) ? (p[u] = findSet(p[u])) : p[u];
}
void link(int x, int y) {
p[x] = y;
}
bool solve() {
int i, j, tmp, x = 0, y = 0;
bool sign = false;
FORE(i, 0, 25) {
if(ru[i] == chu[i])
continue;
if(ru[i] == chu[i] - 1)
++x;
if(ru[i] == chu[i] + 1)
++y;
if(ru[i] - chu[i] > 1 || chu[i] - ru[i] > 1) {
sign = true;
break;
}
}
if(sign)
return false;
FORE(i, 0, 25)
if(ru[i] != 0 || chu[i] != 0) {
tmp = findSet(i);
break;
}
FORE(j, i + 1, 25)
if(ru[j] != 0 || chu[j] != 0)
if(tmp != findSet(j))
return false;
if((x == 1 && y == 1) || (x == 0 && y == 0))
return true;
return false;
}
int main() {
int i;
scanf("%d", &t);
while(t--) {
CLR(ru, 0), CLR(chu, 0);
makeSet();
scanf("%d", &n);
FORE(i, 1, n) {
scanf("%s", ch);
int len = strlen(ch);
if(findSet(ch[len - 1] - 'a') != findSet(ch[0] - 'a'))
link(findSet(ch[len - 1] - 'a'), findSet(ch[0] - 'a'));
++ru[ch[len - 1] - 'a'];
++chu[ch[0] - 'a'];
}
if(solve())
printf("Ordering is possible.\n");
else
printf("The door cannot be opened.\n");
}
return 0;
}
/*
2
2
ok
ko
4
ab
ba
ef
fe
*/