http://acm.nyist.net/JudgeOnline/problem.php?pid=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 ***
-
第一行是一个整数N(0<N<20),表示测试数据的组数
有向图的欧拉回路与无向图又有点不同(条件在代码中已经注释),特别是这题,还要求字典序输出,那么这里我们就先把每一条边进行字典序排序,然后按照字典序从小到大,去匹配符合要求的边。就是根据前面一条边的终点,作为下一条边的起点,去寻找是这个起点的边,最后成功的条件是我们获得n条边,此时可以打完收工。而当可用的边遍历完了之后,仍然不足n条边,那么这时候我们可以给代码改正的机会,我们通过vis[i]=0,进行回溯操作(让程序在某一个分岔口重新选择一个道路去走)。这也是有向图求欧拉回路要比无向图复杂一点的地方,我们要搞清楚区别才不会混淆。
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <cstdio>
using namespace std;
const int MAX = 2000;
struct Edge{
int s, e;
char c[50];
}edge[MAX];
int re[MAX], in[MAX], out[MAX], vis[MAX], n;
bool cmp(const Edge a, const Edge b)
{
return strcmp(a.c, b.c) < 0;
}
int judge()//最多只能有两个点的入度不等于出度,且必须是其中一个点出度恰好比入度大一(作为起点),另一个点入度恰好比出度小一(作为终点)
{
int ans = 0, c1 = 0, c2 = 0;
for(int i = 0; i < 26; i++){
if(abs(in[i]-out[i]) > 1) return -1;//不是欧拉图
else if(in[i] - out[i] == 1) c1++;
else if(in[i] - out[i] == -1) {c2++; ans = i;}
}
if(c1 > 1 || c2 > 1) return -1;//不是欧拉图
if(c2 == 0){
for(int i = 0; i < 26; i++)
if(out[i]) return i;
}
else return ans;
}
int dfs(int u, int cnt)//u表示目前要找的某一条边的出发点,cnt表示这条边的最终的编号
{
if(cnt == n) return 1;//如果不满足cnt==n,说明还没有构成连通图,也就是没有构成欧拉图
for(int i = 0; i < n; i++){
if(u != edge[i].s || vis[i]) continue;//u为起点所对应的边在后面,继续找
vis[i] = 1;
re[cnt] = i;
if(dfs(edge[i].e, cnt+1)) return 1;
vis[i] = 0;//回溯,因为这是有向图,所以回溯很重要
}
return 0;//无法构成欧拉图
}
int main()
{
int T;
scanf("%d", &T);
while(T--){
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%s", edge[i].c);
int len = strlen(edge[i].c);
edge[i].s = edge[i].c[0] - 'a';
edge[i].e = edge[i].c[len-1] - 'a';
out[edge[i].s]++;
in[edge[i].e]++;
}
int ok = judge();//找到起点
if(ok == -1){
printf("***\n");
continue;
}
sort(edge, edge+n, cmp);
memset(vis, 0, sizeof(vis));
if(!dfs(ok, 0)){
printf("***\n");
continue;
}
printf("%s", edge[re[0]].c);
for(int i = 1; i < n; i++)
printf(".%s", edge[re[i]].c);
printf("\n");
}
return 0;
}