原题链接: http://acm.hdu.edu.cn/showproblem.php?
pid=1116
一:原题内容
There is a large number of magnetic plates on every door. Every plate has one word written on it. The plates must be arranged into a sequence in such a way that every word begins with the same letter as the previous word ends. For example, the word ``acm'' can be followed by the word ``motorola''. Your task is to write a computer program that will read the list of words and determine whether it is possible to arrange all of the plates in a sequence (according to the given rule) and consequently to open the door.
If there exists such an ordering of plates, your program should print the sentence "Ordering is possible.". Otherwise, output the sentence "The door cannot be opened.".
3 2 acm ibm 3 acm malform mouse 2 ok ok
The door cannot be opened. Ordering is possible. The door cannot be opened.
二:分析理解
题目大意:给你一些英文单词。推断全部单词能不能连成一串,类似成语接龙的意思。
可是假设有多个反复的单词时,也必须满足这种条件才干算YES。
否则都是不可能的情况。
解题思路:欧拉路的基本题。仅仅要知道就能够做出来了。
关于欧拉回路和欧拉路径
定义:
欧拉回路:每条边恰好仅仅走一次。并能回到出发点的路径
欧拉路径:经过每一条边一次。可是不要求回到起始点
①首先看欧拉回路存在性的判定:
一、无向图
每一个顶点的度数都是偶数,则存在欧拉回路。
二、有向图(全部边都是单向的)
每一个节顶点的入度都等于出度,则存在欧拉回路。
三.混合图欧拉回路
混合图欧拉回路用的是网络流。
把该图的无向边随便定向,计算每一个点的入度和出度。假设有某个点出入度之差为奇数,那么肯定不存在欧拉回路。由于欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
好了,如今每一个点入度和出度之差均为偶数。
那么将这个偶数除以2。得x。也就是说。对于每一个点,仅仅要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出 = 入。假设每一个点都是出 = 入。那么非常明显。该图就存在欧拉回路。
如今的问题就变成了:我该改变哪些边,能够让每一个点出 = 入?构造网络流模型。首先,有向边是不能改变方向的,要之无用。删。
一開始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样。边长容量上限1。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x。对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。
之后。察看是否有满流的分配。有就是能有欧拉回路。没有就是没有。
欧拉回路是哪个?查看流值分配,将全部流量非 0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 =
出度的欧拉图。
因为是满流,所以每一个入 > 出的点,都有x条边进来,将这些进来的边反向。OK,入 = 出了。对于出 > 入的点亦然。
那么。没和s、t连接的点怎么办?和s连接的条件是出 > 入,和t连接的条件是入 > 出,那么这个既没和s也没和t连接的点。自然早在開始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。
我们知道中间点流量不同意有累积的。这样。进去多少就出来多少,反向之后,自然仍保持平衡。
所以,就这样。混合图欧拉回路问题,解了。
②.欧拉路径存在性的判定
一。无向图
一个无向图存在欧拉路径。当且仅当 该图全部顶点的度数为偶数 或者 除了两个度数为奇数外其余的全是偶数。
二。有向图
一个有向图存在欧拉路径,当且仅当 该图全部顶点的度数为零 或者 一个顶点的度数为1,还有一个度数为-1,其它顶点的度数为0。
三。混合图欧拉路径
事实上整篇文章仅仅有这部分是我写的哈,灰常不好意思。仅仅是网上的同志们写的太好了。实在没有必要反复劳动,不知道大家有没有发现。求欧拉路径的第一步一定是求欧拉回路。在混合图上也不例外,怎样推断混合图欧拉回路问题的存在性呢?首先。我们用上文所说的方法推断该图是否存在欧拉回路,假设存在。欧拉路径一定存在。假设欧拉回路不存在,那么我们枚举欧拉路径的起点和终点,连接一条无向边。然后再用最大流推断是否存在欧拉回路就可以。
所以这道题的大题思路就是:
1.并查集推断连通
2.将每一个单词取出首字母和尾字母,转换为一条边,然后增加相应的连通分量中。
假设这个字母出现过。visit数组标记为true。同一时候起点出度加1。终点入度加1.
3.推断一下:
1)这个图必须是连通的,即根结点仅仅有一个。假设不是,直接结束本次算法。
2)假设这个图是连通的。推断每一个结点的入度和出度情况。
假设这个图是欧拉路,则每一个顶点的出度等于入度。
即out[i] = in[i]
假设这个图是半欧拉图。则起点的出度比入度大1。终点的入度比出度大1.其余顶点的出度等于入度。
假设满足上述条件,就能够将全部单词链接起来,否则不能。
当然。在推断出度入度的时候另一点须要注意,那就是除了起点终点以外的顶点。出度必须等于入度(出度入度能够同一时候为2。即环),可是起点和终点必须保证出度和入度之差为1。
三:AC代码
#define _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 #include<iostream> #include<string.h> using namespace std; char ch[1001]; //存储单词 int pre[27]; //一共26个英文字母。下标从1開始,用于并查集 int in[27]; //表示每一个单词的尾部字母的入度,默认是0 int out[27]; //表示每一个单词的头部字母的出度。默认是0 bool visited[27]; //字母是否出现。默认是false int T; //測试实例个数 int N; //每一个实例要输入的单词的个数 int inNum; //推断出现的全部的字母,“入度减出度为1”的个数 int outNum; //推断出现的全部的字母,“出度减入度为1”的个数 int root; //根节点个数 bool flag; //推断出现的全部的字母的出度和入度之差是否是0或1,假设不是。那肯定不满足题意,还有推断root是否大于1,大于1的话。肯定不满足 int start; int last; int Find(int x) { return (x != pre[x]) ? Find(pre[x]) : x; } void Union(int x, int y) { int root_x = Find(x); int root_y = Find(y); if (root_x != root_y) pre[root_x] = root_y; } int main() { cin >> T; while (T--) { for (int i = 1; i < 27; i++) pre[i] = i; memset(in, 0, sizeof(in)); memset(out, 0, sizeof(out)); memset(visited, 0, sizeof(visited)); inNum = outNum = root = 0; flag = true; cin >> N; for (int i = 0; i < N; i++) { cin >> ch; int len = strlen(ch); start = ch[0] - 'a' + 1; last = ch[len - 1] - 'a' + 1; visited[start] = true; visited[last] = true; out[start]++; in[last]++; Union(start, last); } for (int i = 1; i <= 26; i++) { if (visited[i]) { if (pre[i] == i) root++; if (out[i] != in[i])//注意点 { if (out[i] - in[i] == 1) outNum++; else if (in[i] - out[i] == 1) inNum++; else flag = false; } } if (!flag) break; if (root > 1) { flag = false; break; } } if ((flag&&inNum == 0 && outNum == 0) || (flag&&inNum == 1 && outNum == 1)) cout << "Ordering is possible. "; else cout << "The door cannot be opened. "; } return 0; }
參考 :http://www.acmerblog.com/hdu-1116-play-on-words-1412.html