Catenyms
Description
A catenym is a pair of words separated by a period such that the last letter of the first word is the same as the first letter of the second. For example, the following are catenyms:
dog.gophergopher.ratrat.tigeraloha.alohaarachnid.dog
A compound catenym is a sequence of three or more words separated by periods such that each adjacent pair of words forms a catenym. For example,
aloha.aloha.arachnid.dog.gopher.rat.tiger
Given a dictionary of lower case words, you are to find a compound catenym that contains each of the words exactly once.
Input
Output
For each test case, output a line giving the lexicographically least compound catenym that contains each dictionary word exactly once. Output "***" if there is no solution.
Sample Input
Sample Output
这道题就是求给出的单词是否能首尾相连。能就输出他的首尾相连的序列,有多个就按字典序列输出!
这道题一开始我用暴力搜,结果超时了!人家说可以,我个人觉得不行,可能我自己的代码太烂吧!最后没办法百度,原来就是用欧拉回路!顺便说一次下欧拉回路吧!
对无向图:
定义:给定无孤立结点图G,若存在一条路,经过图中每条边一次且仅仅一次,该条路称欧拉路,若存在一条回路,经过图中每边一次且仅仅一次,该回路称为欧拉回路。具有欧拉回路的图称为欧拉图。
定理:无向图G具有一条欧拉路,当且仅当G是连通的,且有0个或者是两个奇数度得结点。
推论:无向图G具有一条欧拉回路,当且仅当G是连通的,并且所有结点的度数均为偶数。
一笔画问题就是典型的这类问题:要判定一个图G是否可一笔画出,有两种情况, 从图中某一个结点出发,经过图G中每个边一次再回到该结点,或者是从G中某一个结点出发,经过G中每边一次且仅一次到达另一个结点,分别对应着欧拉回路和欧拉路的问题
对有向图:
定义:给定有向图G,通过图中每边一次且仅一次的一条单向路(回路),称作单向欧拉路(回路)。
定理:有向图G具有单向欧拉路,当且仅当它是连通的,而且除两个结点外,每个结点的入度等于出度,但这两个结点中,一个结点的入度比出度大1,另一个结点的入度比出度小1。
定理:有向图G具有一条单向欧拉回路,当且仅当是连通的,且每个结点入度等于出度。
代码:(TLE)
#include<algorithm>
#include<string>
using
namespace
std;
struct
edge
{
int
y,end;
char
str[100];
}ss[10005];
bool
cmp(edge a,edge b)
{
return
strcmp
(a.str,b.str)<0;
}
int
da[100000],n,vist[1000000],g;
void
dfs(
int
k)
{
int
j,i;
if
(g==n)
return
;
for
(i=0;i<n;i++)
{
if
(vist[i]==0&&ss[k].str[ss[k].end]==ss[i].str[0])
{
vist[i]=1;
da[g++]=i;
dfs(i);
}
}
}
int
main()
{
int
i,j,fx,fy,T,s,k;
scanf
(
"%d"
,&T);
while
(T--)
{
scanf
(
"%d"
,&n);
for
(i=0;i<n;i++)
{
scanf
(
"%s"
,ss[i].str);
ss[i].y=0;ss[i].end=
strlen
(ss[i].str)-1;
}
sort(ss,ss+n,cmp);
da[0]=0;g=0;
for
(i=0;i<n;i++)
{
memset
(vist,0,
sizeof
(vist));
vist[i]=1;
dfs(i);
}
if
(g==n)
{
printf
(
"%s."
,ss[0].str);
for
(i=0;i<n-1;i++)
printf
(
"%s."
,ss[da[i]].str);
printf
(
"%s"
,ss[da[i]].str);
}
else
printf
(
"***"
);
printf
(
"\n"
);
}
return
0;
}
#include<algorithm>
#include<iostream>
using
namespace
std;
int
in[30],out[30],order[1000],n;
bool
used[1000];
struct
Edge
{
int
st,en;
char
str[30];
}edge[1000];
bool
cmp(Edge a,Edge b)
{
return
strcmp
(a.str,b.str)<0;
}
int
start()
{
int
cnt1=0,cnt2=0,st,i;
for
(i=0;i<26;i++)
{
if
(
abs
(in[i]-out[i])==2)
return
-1;
else
if
(in[i]-out[i]==1)
cnt1++;
else
if
(in[i]-out[i]==-1)
{
cnt2++;
st=i;
}
}
if
(cnt1>1||cnt2>1)
return
-1;
else
if
(cnt1==0)
{
for
(i=0;i<26;i++)
if
(out[i])
return
i;
}
return
st;
}
bool
dfs(
int
st,
int
cnt)
{
int
i;
if
(cnt==n)
return
1;
for
(i=0;i<n;i++)
{
if
(edge[i].st<st||used[i])
continue
;
else
if
(edge[i].st>st)
return
false
;
used[i]=
true
;
order[cnt]=i;
if
(dfs(edge[i].en,cnt+1))
return
1;
used[i]=
false
;
//回溯判断是否形成欧拉路径
}
return
false
;
}
int
main()
{
int
t,i,a,b,len;
cin>>t;
while
(t--)
{
cin>>n;
memset
(used,
false
,
sizeof
(used));
memset
(out,0,
sizeof
(out));
memset
(in,0,
sizeof
(in));
for
(i=0;i<n;i++)
{
scanf
(
"%s"
,edge[i].str);
a=edge[i].str[0]-
'a'
;
len=
strlen
(edge[i].str);
b=edge[i].str[len-1]-
'a'
;
out[a]++;
in[b]++;
edge[i].st=a;
edge[i].en=b;
}
int
st=start();
//寻找起点,先判断是否能形成欧拉路径,条件为所有点入度==出度或者是有一个点的入度比出度大一且还有个点的入度比出度小一
if
(st==-1)
{
cout<<
"***"
<<endl;
continue
;
}
sort(edge,edge+n,cmp);
if
(!dfs(st,0))
{
cout<<
"***"
<<endl;
continue
;
}
printf
(
"%s"
,edge[order[0]].str);
for
(i=1;i<n;i++)
printf
(
".%s"
,edge[order[i]].str);
cout<<endl;
}
return
0;
}