Catenyms
http://poj.org/problem?id=2337
题目大意:
单词首尾相接,问是否可以把所有单词串成一串,如果可以打印出来。
判断是否可以完成其实很简单,普通的有向图判是否存在欧拉路径(degree!=0的点没有,或者之后两个且一个1一个-1)
这一次要打印字典序最小的欧拉路径。
很容易想到先把所有单词读到本地,做一次排序,再将所有单词接到结点a..z上。先特殊判断是否存在欧拉路径(基图连通性判断,degree判断)。
之后用一次深搜打印欧拉路径。
WA了很多次,有两个要注意点,在dfs函数里头:
1、从一个点出发,是可以找到很多环的,多以dfs一次以后不要return,继续找下一个环
2、将所有单词接到结点上要注意是字典序顺序还是逆序的(我习惯加边的方法加进去以后单词变成字典序逆序了),可能要用一个栈来暂存答案,而不能直接输出。
源代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <limits.h>
#include <algorithm>
using namespace std;
#define maxn 26
struct edge{
int v, next, id;
bool vst;
}e[1010];
struct word{
char str[30];
}word[1010];
int n, cnt;
int g[maxn], stack[1010];
bool cmp(struct word a, struct word b)
{
return strcmp(a.str, b.str)>0;
}
void MakeSet(int f[], int a)
{
f[a]=a;
}
int Find(int f[],int a)
{
if(f[a]==a) return a;
return f[a]=Find(f,f[a]);
}
bool Same(int f[],int a,int b)
{
return Find(f,a)==Find(f,b);
}
void Union(int f[],int a,int b)
{
f[Find(f,a)]=Find(f,b);
}
int init()
{
int odd, t1, t2;
int f[26], deg[26];
bool show[26];
scanf("%d", &n);
for (int i=0; i<n; i++)
scanf("%s", word[i].str);
sort(word, word+n, cmp);
memset(g, 255, sizeof(g)); //边
memset(deg, 0, sizeof(deg)); //度数
memset(show, 0, sizeof(show));
for (int i=0; i<26; i++)
MakeSet(f, i);
for (int i=0, j=0; i<n; i++)
{
t1=word[i].str[0]-'a';
t2=word[i].str[strlen(word[i].str)-1]-'a';
deg[t1]--;
deg[t2]++;
show[t1]=show[t2]=true;
Union(f, t1, t2);
e[j].v=t2; e[j].id=i; e[j].vst=false; e[j].next=g[t1]; g[t1]=j++;
}
for (int i=0; i<26; i++) //判连基图的连通性
if (show[i])
{
for (int j=i+1; j<26; j++)
if (show[j] && !Same(f, i, j))
return -1;
break;
}
odd=0;
for (int i=0; i<26; i++)
if (show[i] && deg[i]!=0)
{
if (deg[i]!=1 && deg[i]!=-1) return -1;
if (odd==0) t1=i;
else if (odd==1) t2=i;
odd++;
if (odd>2) return -1;
}
if (odd==1) return -1;
else if (odd==2) //不存在欧拉回路,只存在欧拉路径
{
if (deg[t1]+deg[t2]!=0)
return -1;
if (deg[t1]==-1)
return t1;
else
return t2;
}
for (int i=0; i<26; i++) //存在欧拉回路,字典序最小的点开始
if (show[i]) return i;
return -1;
}
void dfs(int k, int eid)
{
for (int i=g[k]; i!=-1; i=e[i].next)
if (e[i].vst==false)
{
e[i].vst=true;
dfs(e[i].v, i);
}
if (eid!=-1)
stack[cnt++]=e[eid].id;
}
int main()
{
int cs, t;
scanf("%d", &cs);
while (cs--)
{
t=init();
if (t==-1)
{
printf("***\n");
continue;
}
else
{
cnt=0;
dfs(t, -1);
printf("%s", word[stack[cnt-1]].str);
for (int i=cnt-2; i>=0; i--)
printf(".%s", word[stack[i]].str);
printf("\n");
}
}
return 0;
}