首先是题目本身
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.
题意就不赘述了 题目的目的是要输入一些单词 判断是否可以“前一个单词的最后一个字母是后一个单词的第一个字母 ”判断给出的一组单词是否可完成这样一个句子
做题时自己的想法确实想不到要明确这道题就是用并查集和欧拉回路 于是自己用自己的思路写 结果自然是没有过
听完讲题之后 恩 要用并查集 欧拉回路 也没去了解欧拉回路的详细情况 就根据那个入度出度感觉很有用 于是就不管了 自己写 但wrong answer应该是有特殊情况没考虑到 于是觉得还是不能非主流写法了 特立独行对于做题还是不行啊
今天我想的还是不用并查集来做这道题 但是发现欧拉回路的判断跟我的程序是相同的条件 那么问题就出在了没有用并查集 自己想了些样例 发现只有aa bb cc这种样例会得出错误的答案 因为它们的入度等于出度 但是并没有判定是否可以连起来
先写个并查集的小函数 想一想思路
运用并查集的话 对于aa bb 设第一个字母是最后一个字母的父节点,如果存在了两个及以上的根节点 就是错误的 换个样例:ab bc cd ff看来需要压缩路径然后判断所有的根节点是不是同一个 如果不是的话则错误 再试一个正确的例子 ab bc cd bb感觉好像出了点问题 可以把bb单独拿出来判断 但是并查集的判断应该是在欧拉回路之前 还是试一试 将所有形如aa bb 的单词单独提出 判断其他点是否连成一条 再判断其中是否有一个出度入度相同的字母或者是最多两个两个出入度差为1的点 为什么感觉想的很复杂啊 重新回到并查集的判断试一试
连成一条路即表示只有一个根节点 所以不需要判断根节点是否相等 只需要判断有几个根节点就可以了
一天 未果 因为判定所有点是否只有一个根节点这里总是出问题
现在是2017年1月27下午五点44 我今天下午准备去网上找一找题解 因为自己也对自己判断是否只有一个根节点不太放心 结果想想还是自己再改改
我个人喜欢自己做 高中就是这样 宁愿不做也不愿意抄答案 大概是觉得自己写出来很有成就感吧
于是测试样例 发现自己的一部分答案有时候对有时候不对 总之第一次输入的都是正确的
于是想到 肯定是某个变量每一次循环的时候没有重置 然后就找到了一个后面加上的mark变量! 这个时候其实交上去还是觉得估计真的要去找题解了
不是不看题解 我也会去看其他的思路 但是不会复制别人的
结果! 一瞬间就绿了!
对了 我自己判断是否一个根节点的方法是 先遍历一遍 一旦发现一个根节点 记录下值 break; 然后再遍历 一旦出现和它不同值的根节点 break; mark变为1;
然后就是欧拉回路的一个单向图 一个环 两种情况的判断
接下来放代码 之前的想法思路保留了一部分 注释掉了
#include<cstdio>
#include<string.h>
using namespace std;
int find(int x);
void myunion(int x, int y);
int pre[30], flag[30];
int main()
{
int n1, n2, i, j, z, x, l[30], r[30], same[30], f, b, p, q, o, h, k = 0, v, w,ww;
char ss[1010];
int mark;
scanf("%d", &n1);
for (i = 0; i < n1; i++)
{
for (z = 0; z < 27; z++)
{
flag[z] = 0;
l[z] = 0;
r[z] = 0;
same[z] = 0;
pre[z] = z;
}
k = 0;
scanf("%d", &n2);
if (n2 == 1)
{
scanf("%s", ss);
printf("Ordering is possible.\n");
}
else
{
for (j = 0; j < n2; j++)
{
memset(ss, 0, 27);
scanf("%s", ss);
x = strlen(ss);
f = ss[0] - 96;
b = ss[x - 1] - 96;
l[f]++;
r[b]++;
flag[f] = 1;
flag[b] = 1;
myunion(f, b);
/* if (f == b)
{
same[f] = same[f] + 1;
k++;
}*/
}
p = 0;
q = 0;
o = 0;
// for (w = 1; w <= 26; w++)
mark = 0;
for (w = 1; w <= 26; w++)
{
ww = w;
if (flag[w] == 1)
{
v=find(ww);
break;
}
}
for(int bb=ww;bb<=26;bb++)
{
if(flag[bb]==1&& find(bb) !=v)
mark = 1;
}
if (mark == 1)printf("The door cannot be opened.\n");
else
{
for (j = 1; j <= 26; j++)
{
h = l[j] - r[j];
/*if (same[j] > 0)
{
if (h == 1 || h == -1 || (h == 0 && l[j] != 0 && r[j] != 0))
{
flag = flag + same[j];
}
}*/
if (h == 1)p++;
if (h == -1)q++;
if (h == 0)o++;
}
if ((o == 24 && p == 1 && q == 1) || (o == 26))
printf("Ordering is possible.\n");
else
{
printf("The door cannot be opened.\n");
}
}
}
}
}
int find(int c)
{
while (c != pre[c])
c = find(pre[c]);
return c;
}
void myunion(int xxx, int yyy)
{
int dx, dy;
dx = find(xxx);
dy = find(yyy);
if (dx != dy);
pre[dy] = dx;
}
心情复杂 算是年前给自己的一个鼓励吧 ACM 这条路我还会走下去 突然想写点东西 我靠突然想起 之前训练的总结还没有写!!!!! (当我没说 默默补上)