NYOJ99单词拼接

单词拼接

时间限制: 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

我先在网上找了并查集的:


代码1:

 
#include <iostream> 
#include <cstdio> 
#include <cstring> 
using namespace std; 
struct adjLink 
{     
	int v, nxt;      
	char word[30];  
}adj[2000];  
int adjN;  
void insert(int beg, int end, char word[30])//类似于hash,第一个节点数据域不存值只有指针部分有效。链表中单词按字典序排列。 
{      
	int i;  
	for (i = beg; adj[i].nxt != -1; i = adj[i].nxt)
		if (strcmp(adj[adj[i].nxt].word, word) >= 0) break;  
	adj[adjN].v = end;
	strcpy(adj[adjN].word, word);
	adj[adjN].nxt = adj[i].nxt;
	adj[i].nxt = adjN++;  
} 
int vis[30], count;  
void dfs(int cur)//检查连通性 
{  
	vis[cur] = 1; 
	count++;
	for (int i = adj[cur].nxt; i != -1; i = adj[i].nxt)    
	if (!vis[adj[i].v])     
		dfs(adj[i].v);  
} 
int path[2000], npath;  
void euler(int cur, int edgeN) //cur当前到达的节点 edgeN上一被选择的边,即上一个节点通过edgeN到达的cur 
{      
	int i;
	while(adj[cur].nxt != -1)
	{    
		i=adj[cur].nxt;
		adj[cur].nxt=adj[i].nxt;
		euler(adj[i].v,i);
	}
	path[npath++] = edgeN; //后序记录 输出的时候为了保证字典序,需逆向输出 
}  
void go() 
{
	int n, i;
	scanf("%d", &n);
	for (i = 0; i < 26; i++)
		adj[i].nxt = -1;
	adjN = i;
	int flag[30], tot = 0, cnt[30];
	memset(flag, 0, sizeof(flag));
	memset(cnt, 0, sizeof(cnt));
	for (i = 0; i < n; i++)
	{
		char word[30];
		scanf("%s", word);
		int a = word[0] - 'a', b = word[strlen(word) - 1] - 'a';
	//	int len = strlen(word);
	//	word[len] = '.'; 
	//	word[len + 1] = 0;  
		insert(a, b, word);
		cnt[b]--;
		cnt[a]++;
		if (!flag[a])
			flag[a] = 1, tot++;
		if (!flag[b])
			flag[b] = 1, tot++;
	}
	for (i = 0; i < 26; i++)
	{    
		memset(vis, 0, sizeof(vis));
		count = 0;
		dfs(i);
		if (count == tot) break;
	}
	if (i == 26)
	{   
		printf("***\n");
		return ;
	} 
	int flagIn = 0, flagOut = 0, flagNo = 0, site;
	for (i = 0; i < 26; i++)    
	if (cnt[i] == -1)        
		flagIn++;
	else if (cnt[i] == 1)        
		flagOut++, site = i;
	else   if (cnt[i])          
		flagNo = 1;  
	if (flagNo || flagIn > 1 || flagOut > 1 || flagIn != flagOut)//根据欧拉通路的充要条件 将不符合的先排除掉
	{    
		printf("***\n");
		return ;
	}
	npath = 0;
	if (flagOut == 0)
	{    
		for (i = 0; i < 26; i++) 
		if (adj[i].nxt != -1)      
		{
			site = i;
			break;
		}
	}
	euler(site, -1); //因为直接从site出发,所以第二个参数用-1代替,输出的时候要忽略掉.
	for (i = npath - 2; i > 0; i--)
		printf("%s.", adj[path[i]].word);
//	int len = strlen(adj[path[0]].word);
//	adj[path[0]].word[len-1] = 0;//多一个.,所以len大1
	printf("%s\n", adj[path[0]].word);  
} 
int main() 
{      
	int T;
	scanf("%d", &T);
	while (T--)    
		go();      
	return 0;  
}         

代码2:

 
 
#include<stdio.h>  
#include<string.h>
# define N 1000  
# define X 26
int P[X+1],path[N],IN[X],OUT[X],EE[X];
char T[N][31],S[2][N],*tt[N],VIS[N],*W;  
void Link(int P[],int x,int y);
int find(int P[],int x);
void Qsort(int L,int R);//快速排序升序 
void change(char *a,char *b)
{                             //交换函数    
    char c=*a;    
    *a=*b;    
    *b=c;    
} 
int DFS(int U,int m,int C);   
int main(){
	int m,n,i,j,k,L=-1,ca,cb,cc,start;
	//freopen("ttt.txt","r",stdin);
   scanf("%d",&n);
   while(n--){
   	for(i=0;i<X;i++)
   	   P[i]=i;	
   	scanf("%d",&m);
   	for(i=0;i<m;i++,L=-1)
   	{
   		tt[i]=T[i];
   		scanf("%s",&T[i]);
   		while(T[i][++L]);
   		S[0][i]=T[i][0]-'a';
   		S[1][i]=T[i][L-1]-'a';
   		Link(P,S[0][i],S[1][i]);
   		IN[S[1][i]]++;
   		OUT[S[0][i]]++;
   		EE[S[0][i]]=EE[S[1][i]]=1;
   		VIS[i]=0;
   	}
   	Qsort(0,m-1);
   	for(ca=cb=cc=start=i=0;i<X;i++)
   	{
   		if(EE[i]&&P[i]==i){
   			ca++;
   		   if(ca>1)break;
   		}
   		if(IN[i]==OUT[i])continue;
   		else
	      {
   			if(IN[i]==OUT[i]+1)cb++;
   			else if(IN[i]==OUT[i]-1)
   			{
   				cc++;
   				start=i;
   			}
   			else break;
   	      }	
   	}
   	if((cb==cc||cb<2)&&i==X&&DFS(start,m,0))
   	{
   	   printf("%s",tt[path[0]]);
   	   for(i=1;i<m;i++)
   	      printf(".%s",tt[path[i]]);
   	   printf("\n");
   	}
   	else
   	printf("***\n");
   	for(i=0;i<X;i++)
   	 IN[i]=EE[i]=OUT[i]=0;
   }
   return 0;
}
int find(int P[],int x)  
{  
    while(x!=P[x])x=P[x];  
    return x;  
}  
void Link(int P[],int x,int y)  
{  
    int fy=find(P,y),fx=find(P,x);  
    if(fy!=fx) P[fy]=fx;  
}  
void Qsort(int L,int R)//快速排序 升序   
{  
    int i=L,j=R;
	char *temp=tt[L]; 
    if(L>R)  return;  
    while(i!=j) //当数组左右两边没相遇  
    {  
        while(strcmp(tt[j],temp)>=0&&i<j)j--;  //从右向左找  改为while(A[j]<=T&&i<j)  
        while(strcmp(tt[i],temp)<=0&&i<j)i++; //从左向右找   改为while(A[i]>=T&&i<j) 这两处 改完即为降序   
        if(i<j){
        	change(&S[0][i],&S[0][j]);
        	change(&S[1][i],&S[1][j]);
        	W=tt[i];tt[i]=tt[j];tt[j]=W;
        } //交换两数  
    }  
if(L!=i){
        	change(&S[0][i],&S[0][L]);
        	change(&S[1][i],&S[1][L]);
        	W=tt[i];tt[i]=tt[L];tt[L]=W;
        }        //基准数归位  
    Qsort(L,i-1);         //递归左  
    Qsort(i+1,R);         //递归右  
}  
int DFS(int U,int m,int C)
{
	int F=0,i;
	if(C==m)return 1;
	for(i=0;i<m;i++)
	{
		if(!VIS[i]&&S[0][i]==U)
		{
			VIS[i]=1;
			path[C]=i;
			F=DFS(S[1][i],m,C+1);
			VIS[i]=0;
			if(F)return 1;
		}
	}
	return 0;
}                




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值