单词游戏

单词游戏 

题目描述

来自 ICPC CERC 1999/2000,有改动。

有 N 个盘子,每个盘子上写着一个仅由小写字母组成的英文单词。你需要给这些盘子安排一个合适的顺序,使得相邻两个盘子中,前一个盘子上单词的末字母等于后一个盘子上单词的首字母。请你编写一个程序,判断是否能达到这一要求。如果能,请给出一个合适的顺序。

输入格式

多组数据。第一行给出数据组数T,每组数据第一行给出盘子数量 N,接下去 N 行给出小写字母字符串,一种字符串可能出现多次。

输出格式

若存在一组合法解输出Ordering is possible.,否则输出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.
数据范围与提示

1N10^5,S1000

 

It's a good problem,这是一道判断有无欧拉路的题,欧拉路及欧拉回路的题码量不大,下面我来简述一下这道题

首先,我们看到首尾相连,可以想到向首到尾连一条边

即若单词为handsomeboy,则从h连向y即可,这一条路是什么意思呢?这说明选一个单词,前一个单词要么不选要么就选一首为结尾的单词,尾亦然

连完边后,题目就变成了求原图中是否有欧拉路径

欧拉回路亦可,例如:ab,ba,这就是一个欧拉回路,但是由于一条边可以不走,所以也可行

判断是否为欧拉路径的方法: 1.原图中只有一个入度比出度多一的点和一个入度比出度少一的点  2.原图是连通图

然后就可以AC了

上代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int in[30],out[30],t,n,sum,tot=-1,fir[30],nxt[200005],to[200005],firs[30];
char a[100500];
bool check(){
	int zlk=0,wyx=0;
	rep(i,0,25){
		if(abs(in[i]-out[i])>1) return 0;
		if(in[i]-out[i]==1) ++zlk;
		else if(out[i]-in[i]==1) ++wyx;
	}
	if(zlk==1 && wyx==1) return 1;
	if(!zlk && !wyx) return 1;
	return 0;
}
void ade(int u,int v){
	to[++tot]=v;
	nxt[tot]=fir[u];
	fir[u]=tot;
}
void euler(int x){
	while(fir[x]){
		int k=fir[x];
		fir[x]=nxt[k];
		euler(to[k]);
		++sum;
	}
}
int main(){
	//freopen("1.txt","r",stdin);
//	freopen("1.out","w",stdout);
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		memset(fir,0,sizeof(fir)); tot=0;
		memset(in,0,sizeof(in));
		memset(out,0,sizeof(out));
		rep(i,1,n){
			scanf("%s",a);
			in[a[strlen(a)-1]-'a']++;
			out[a[0]-'a']++;
			ade(a[0]-'a',a[strlen(a)-1]-'a');
		}
		rep(i,0,25) firs[i]=fir[i];
		if(!check()) puts("The door cannot be opened.");
		else{
			rep(i,0,25){
				sum=0;
				if(fir[i]!=-1){
					euler(i);
					if(sum==n){
						sum=-1;
						puts("Ordering is possible.");
						break;
					}
				}
				rep(j,0,25) fir[j]=firs[j];
			}
			if(sum!=-1) puts("The door cannot be opened.");
		}
	}
	return 0;
}

  

转载于:https://www.cnblogs.com/handsome-zlk/p/10186747.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值