NYOJ 99-单词拼接(欧拉通路)

单词拼接

时间限制: 3000 ms  |  内存限制: 65535 KB
难度: 5
描述

给你一些单词,请你判断能否把它们首尾串起来串成一串。

前一个单词的结尾应该与下一个单词的道字母相同。

aloha

dog

arachnid

gopher

tiger

rat

 

可以拼接成:aloha.arachnid.dog.gopher.rat.tiger

输入
第一行是一个整数N(0<N<20),表示测试数据的组数
每组测试数据的第一行是一个整数M,表示该组测试数据中有M(2<M<1000)个互不相同的单词,随后的M行,每行是一个长度不超过30的单词,单词全部由小写字母组成。
输出
如果存在拼接方案,请输出所有拼接方案中字典序最小的方案。(两个单词之间输出一个英文句号".")
如果不存在拼接方案,则输出
***
样例输入
2
6
aloha
arachnid
dog
gopher
rat
tiger
3
oak
maple
elm
样例输出
aloha.arachnid.dog.gopher.rat.tiger
***
来源
Waterloo local 2003.01.25 /POJ
上传者

张云聪


一开始是爆搜,超时,然后用vector剪了一波枝,就开始永无止境的wa了,找了将近两小时的样例,也没找到错误,不知道为啥,最近经常这样,造数据的能力太弱?好吧,是我太菜,于是换了种思路,根据欧拉回路的性质首先判断能否构成欧拉通路,然后找起点和终点,并保存起点,怎么找起点呢,我们首先对所有字符串按照字典序排序,因为要保证字典序最小,之后标记每个单词的两端,串首代表该字符的出度,串尾代表入度。为什么要这样定义呢??当然,反着来也是可以的,看你怎么理解了。。。接下来就是找起点了,一个点可以当做起点的条件当且仅当该点的出度比入度大一或者所有点的出度和入度相同,不难证明,详情见代码中的euler函数部分。。

#include<map>          
#include<stack>          
#include<queue>          
#include<vector>          
#include<math.h>          
#include<stdio.h>          
#include<iostream>          
#include<string.h>          
#include<stdlib.h>  
#include<algorithm> 
#include<functional>  
using namespace std;          
typedef long long  ll;          
#define inf  1000000000         
#define MOD 1000000007           
#define  maxn  1005
#define  lowbit(x) (x&-x)          
#define  eps 1e-9
struct node
{
	char s[35];
}a[maxn],b[maxn];
int vis[maxn],n,cnt,in[30],out[30],rt[maxn];
bool comp(node a,node b)
{
	if(strcmp(a.s,b.s)<0)
		return 1;
	return 0;
}
int euler()
{
	int i,st=-1,ed=-1;
	for(i=0;i<26;i++)
	{
		if(out[i]==in[i])
			continue;
		if(out[i]-in[i]==1 && st==-1)
			st=i;
		else if(out[i]-in[i]==-1 && ed==-1)
			ed=i;
		else
			return -1;
	}
	//printf("%d %d\n",st,ed);
	if(st>-1 && ed>-1)
		return st;
	if(st==-1 && ed==-1)
	{
		for(i=0;i<26;i++)
			if(out[i]!=0)
				return i;
	}
	return -1;
}
int dfs(int st,int id)
{
	if(id==n+1)
		return 1;
	for(int i=1;i<=n;i++)
	{
		if(vis[i] || a[i].s[0]-'a'<st)
			continue;
		if(a[i].s[0]-'a'>st)
			break;
		rt[id]=i;vis[i]=1;
		int len=strlen(a[i].s);
		if(dfs(a[i].s[len-1]-'a',id+1))
			return 1;
		vis[i]=0;
	}
	return 0;
}
int main(void)
{
	int T,i,j;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		memset(in,0,sizeof(in));
		memset(out,0,sizeof(out));
		memset(vis,0,sizeof(vis));
		for(i=1;i<=n;i++)
		{
			scanf("%s",a[i].s);
			out[a[i].s[0]-'a']++;
			int len=strlen(a[i].s);
			in[a[i].s[len-1]-'a']++;
		}	
		int st=euler();
		if(st==-1)
		{
			printf("***\n");
			continue;
		}
		sort(a+1,a+n+1,comp);	
		if(dfs(st,1))
		{
			for(i=1;i<n;i++)
				printf("%s.",a[rt[i]].s);
			printf("%s\n",a[rt[n]].s);
		}
		else
			printf("***\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值