NYOJ99
思路 : 把 单词两端的字母看成点,单词本身看成一个权重一样,用来排序以谁为开头。
只需判断是否欧拉图
根据入度出度判断
判断是否连通 (并查集)
若是,再深搜输出路径。
参考:
nyoj 单词拼接(并查集判断连通性+欧拉路径)
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
int f[26],in[26],out[26],vis[1005],path[1005],ext[1005];
struct node
{
int u,v;
char a[31];
}an[1005];
int cmp(struct node b ,struct node c)
{
return strcmp(b.a ,c.a) < 0 ;
}
void init()
{
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(ext,0,sizeof(ext));
int i;
for(i = 0;i<26;i++)
{
f[i] = i;
}
}
int find(int a)
{
if( f[a] == a )return a;
return find(f[a]);
}
void merge(int u ,int v)
{
int l = find(u);
int r = find(v);
f[r] = l;
}
int dfs(int u , int n , int cen)
{
if(cen == n )return 1;
int f =0,i;
for(i = 0;i<n;i++ )
{
if(vis[i] == 0 && an[i].u == u )
{
vis[i] = 1;
path[cen] = i;
f = dfs(an[i].v ,n, cen+1);
vis[i] = 0;
if(f == 1)return 1;
}
}
return 0;
}
int main()
{
int M,n,l;
int i,j,k,c,c1,c2,start;
char a[31];
scanf("%d",&M);
while(M--)
{
init();
scanf("%d",&n);
for(i = 0;i<n;i++)
{
scanf("%s",&a);
l = strlen(a);
an[i].u = a[0] -'a';
an[i].v = a[l-1] -'a';
strcpy(an[i].a , a );
merge(an[i].u,an[i].v);
}
sort(an,an+n,cmp);
for(i = 0;i<n;i++)
{
in[an[i].v]++;
out[an[i].u]++;
ext[an[i].v] = ext[an[i].u] = 1;
}
start = 0;c= 0;c1 = c2 = 0;
for(i = 0;i<26;i++)
{
if(ext[i] && f[i] == i )//联通判断 只允许存在的点中同属于一个集合,即只有一个点等于它本身
{
c++;
if(c>1)break;
}
if(in[i] == out[i])continue;
else
{
if( in[i] == out[i] +1)c1++;
else if( in[i] + 1 == out[i])
{
c2++;start = i; //标记深搜的起始位置
}
else break;
}
}
if((c1 == c2 || (c1<2) )&& i==26 && dfs(start,n,0)) //dfs可放入if条件里面
{
printf("%s",an[path[0]].a);
for(i = 1;i<n;i++)
{
printf(".%s",an[path[i]].a);
}
printf("\n");
continue;
}
printf("***\n");
}
}