UVA10129 单词 Play on Words 欧拉回路的判断
题意翻译
输入n(n\leq100000)n(n≤100000)个单词,是否可以把所有这些单词排成一个序列,使得每个单词的第一个字母可上一个单词的最后一个字母相同(例如acm,malform,mouseacm,malform,mouse)。每个单词最多包含10001000个小写字母。输入中可以有重复的单词。
输入输出样例
输入 #1复制
3 2 acm ibm 3 acm malform mouse 2 ok ok
欧拉道路:能否从无向图的一个结点出发走出一条道路,每条边恰好经过一次。这样的路线称为欧拉道路。
在一个联通的图中除了‘起点’‘终点’其余点的‘进’和‘出’(在有向图中分入度和出度)应该是相等的,也就是每个点的度都是偶数。
在无向图中最多有两个点是奇点(度是奇数),有两个奇点则一定从一个奇点出发到另一个奇点结束。若都是偶点则可从任意点出发最后回到该点。
在有向图中类似:最多只有两个点入读不等于出度。且互相差为1;从出度大1的点起始到入读大1的点结束。
该题可以把单词看作有向图,判断是否有欧拉道路,先判断是否联通,再判断度的关系是否满足;
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
const int N = 27;
int m, n, x, y, p;
int in[N], ans[N], out[N], G[N][N], vis[N];
string c;
void dfs(int u)
{//判断图是否联通
vis[u] = 0;//将该点标记为在图中;
for (int v = 0; v < 26; ++v) {
if (G[u][v]&&vis[v]) {//如果u,v,连接且v不在图中递归放到图中;
dfs(v);
}
}
}
bool solve()
{
cin >> n;
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(G, 0, sizeof(G));
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; ++i) {
cin >> c;
//scanf("%c",&c);
x = c[0] - 'a', y = c.back() - 'a';
G[x][y] = G[y][x] = 1;//因为欧拉回路是判断无向图是否连通
vis[x] = vis[y] = 1;//标记出现的字母节点
out[c[0] - 'a']++;
in[c.back() - 'a']++;
}
dfs(x);
bool begin = false, end = false;
for (int i = 0; i < 26; ++i) {
if (vis[i])return false;//如果有字母存在且不再图中则不存在欧拉回路
if (in[i] == out[i])continue;
else {
if (in[i] - out[i] == 1 && !end) {
end = 1;
}
else if (out[i] - in[i] == 1 && !begin) {
begin = 1;
}
else {
return false;
}
}
}
return begin == end;
}
int main()
{
cin >> m;
while (m--)
{
if (solve()) {
cout << "Ordering is possible.";
}
else cout << "The door cannot be opened.";
cout << endl;
}
return 0;
}
#include<iostream>
#include<cstring>
#include<string>
#include<stack>
using namespace std;
const int N = 27;
int m, n, x, y, p, cnt;
int in[N], out[N], G[N][N], vis[N];
int map[N][N];
string c;
void dfs(int u)
{//判断图是否联通
vis[u] = 0;//将该点标记为在图中;
for (int v = 0; v < 26; ++v) {
if (G[u][v]&&vis[v]) {//如果u,v,连接且v不在图中递归放到图中;
dfs(v);
}
}
}
stack<int> ans;
void dfs2(int u)
{//打印路径
//cout << (char)(u+'a') << " ";
ans.push(u); cnt--;
for (int v = 0; v < 26&&cnt!=-1; ++v) {//寻找新的出发点
if (map[v][u]) {
map[v][u]--;
dfs2(v);
map[v][u]++;
}
}
if (cnt == -1)return;
cnt++;
ans.pop();
}
bool solve()
{
cin >> n;
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(G, 0, sizeof(G));
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; ++i) {
cin >> c;
cnt++;
//scanf("%c",&c);
x = c[0] - 'a', y = c.back() - 'a';
G[x][y] = G[y][x] = 1;//因为欧拉回路是判断无向图是否连通
map[x][y]++;
vis[x] = vis[y] = 1;//标记出现的字母节点
out[c[0] - 'a']++;
in[c.back() - 'a']++;
}
dfs(x);
bool begin = false, end = false;
for (int i = 0; i < 26; ++i) {
if (vis[i])return false;//如果有字母存在且不再图中则不存在欧拉回路
if (in[i] == out[i])continue;
else {
if (in[i] - out[i] == 1 && !end) {
end = 1; y = i;
}
else if (out[i] - in[i] == 1 && !begin) {
begin = 1; x = i;
}
else {
return false;
}
}
}
return begin == end;
}
int main()
{
cin >> m;
while (m--)
{
cnt = 0;
if (solve()) {
dfs2(y);
while (!ans.empty()) {
cout << (char)(ans.top()+'a') << ' ';
ans.pop();
}
cout << "Ordering is possible.";
}
else cout << "The door cannot be opened.";
cout << endl;
}
return 0;
}