play on words又是一道改了很久的题

首先是题目本身

Some of the secret doors contain a very interesting word puzzle. The team of archaeologists has to solve it to open that doors. Because there is no other way to open the doors, the puzzle is very important for us. 

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. 
Input
The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing a single integer number Nthat indicates the number of plates (1 <= N <= 100000). Then exactly Nlines follow, each containing a single word. Each word contains at least two and at most 1000 lowercase characters, that means only letters 'a' through 'z' will appear in the word. The same word may appear several times in the list. 
Output
Your program has to determine whether it is possible to arrange all the plates in a sequence such that the first letter of each word is equal to the last letter of the previous word. All the plates from the list must be used, each exactly once. The words mentioned several times must be used that number of times. 
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.". 
Sample Input
3
2
acm
ibm
3
acm
malform
mouse
2
ok
ok
Sample Output
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 这条路我还会走下去   突然想写点东西   我靠突然想起   之前训练的总结还没有写!!!!!   (当我没说  默默补上)   


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值