nyoj 拼单词

拼单词

描述

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

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

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
***

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

char word[1010][30];
int indegree[30],oudegree[30];
int n,trace[1010],vis[1010],len[1010];
int Euler()
{
	int i,start = -1,end = -1;
	for(i=0;i<26;i++)
	{
		//感觉这里是技巧,我原来写的是将入度等于出度的也计数;
		//显然这样写更好;
		if(oudegree[i]!=indegree[i])
		{
			//出度比入度大一,是起点;
			if(oudegree[i]==indegree[i]+1&&start==-1)
				start = i;
			//出度比入度小一,是终点;
			else if(oudegree[i]+1==indegree[i]&&end==-1)
				end = i;
			else
				return -1;
		}
	}
	//这里的条件必须是同时成立,如果起点和终点只有一个,是不存在欧拉路的
	if(start>-1&&end>-1)
		return start;
	else if(start==-1&&end==-1)//当图中存在欧拉回路的时候会执行这里
		return 0;    //因为单词已经排过序,所以返回0,在dfs中就能找到字典序最小的排序
	else
		return -1;
}

//dfs包含的判断图是否联通图的问题;
int dfs(char start,int index)
{
	if(index==n)
		return 1;
	int i,begin = 0,end = n - 1,mid;
	while(begin<=end)
	{
		mid = (begin+end)>>1;
		if(word[mid][0]==start)
			break;
		else if(word[mid][0]>start)
			end = mid - 1;
		else
			begin = mid + 1;
	}
	if(begin>end)
		return 0;

	//这里是当qsort之后 以某个字母开头的单词有多个是,我们要从第一个开始;
	while(word[mid][0]==start&&mid>=0)
		mid--;
	for(i=mid+1;word[i][0]==start;i++)
	{
		if(!vis[i])
		{
			trace[index] = i;
			vis[i] = 1;
			if(dfs( word[i][len[i]-1],index+1 ) )
				return 1;
			vis[i] = 0;
		}

	}
	return 0;
}

int cmp(const void *a,const void *b)
{
	return (strcmp((char *)a,(char *)b));
}

int main()
{
	int t,i,cont;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		memset(oudegree,0,sizeof(oudegree));
		memset(indegree,0,sizeof(indegree));
		memset(vis,0,sizeof(vis));
		for(i=0;i<n;i++)
			scanf("%s",word[i]);

		qsort(word,n,30,cmp);
		memset(len,0,sizeof(len));
		for(i=0;i<n;i++)
		{
			len[i] = strlen(word[i]);
			oudegree[word[i][0]-'a']++;
			indegree[word[i][len[i]-1]-'a']++;
		}
		
		cont = Euler();
		//printf("cont: %d\n",cont);
		if(cont!=-1&&dfs(cont+'a',0))
		{
			for(i=0;i<n-1;i++)
				printf("%s.",word[trace[i]]);
			printf("%s\n",word[trace[n-1]]);
		}
		else
			printf("***\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值