题目:http://poj.org/problem?id=2337
分析:根据题目的意思可以想到两个方向:①把字符串当做点,两点能形成接龙形式则连一条有向边,这是问题变成求一条点不重复的路且经过每一个点。这就像一个路径覆盖问题,但是图上各种多重边让笔者不知道怎么搞所以放弃这个想法;②把字符串当做边,以26个字母为顶点建图,问题变成求边不重复的路且经过每一条边,显然这是求欧拉通路。
PS:码代码是为了求快搞了各种贪心的搞法,然后各种RE。。。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
struct edge
{
int v,used;
string s;
bool operator<(const edge &x)const
{
return s<x.s;
}
edge(int _v,int _u,string _s):v(_v),used(_u),s(_s){};
};
vector<edge> vec[30],e;
struct node
{
int in,out;
}nd[30];
int pre[30],vis[30];
int cnt,n,tt;
void dfs(int u)//判连通
{
vis[u]=1;tt++;
for(int i=0;i<vec[u].size();i++)
{
int v=vec[u][i].v;
if(!vis[v])dfs(v);
}
}
bool path(int u,int dep)//求欧拉通路
{
if(dep==n)return true;
for(int i=0;i<vec[u].size();i++)
{
if(vec[u][i].used)continue;
vec[u][i].used=1;
if(path(vec[u][i].v,dep+1))
{
e.push_back(edge(vec[u][i].v,0,vec[u][i].s));
return true;
}
vec[u][i].used=0;
}
return false;
}
int main()
{
int t;
scanf("%d",&t);getchar();
while(t--)
{
scanf("%d",&n);getchar();
memset(nd,0,sizeof(nd));
for(int i=0;i<26;i++)vec[i].clear();
for(int i=0;i<n;i++)
{
char s[25];
scanf("%s",s);
int u=s[0]-'a';
int v=s[strlen(s)-1]-'a';
nd[u].out++;nd[v].in++;
vec[u].push_back(edge(v,0,s));
}
int tot=0,flag=0;
for(int i=0;i<26;i++)if(nd[i].out+nd[i].in>0)tot++;
memset(vis,0,sizeof(vis));
for(int i=0;i<26;i++)
{
tt=0;
if(nd[i].out)
{
memset(vis,0,sizeof(vis));
dfs(i);
}
if(tt==tot){flag=1;break;}
}
if(!flag){printf("***\n");continue;}
int num=0;flag=1;
for(int i=0;i<26;i++)
{
if(nd[i].in!=nd[i].out)
{
if(abs(nd[i].in-nd[i].out)==1)num++;
else flag=0;
}
}
if((num!=0&&num!=2)||flag==0){printf("***\n");continue;}
for(int i=0;i<26;i++)if(vis[i])sort(vec[i].begin(),vec[i].end());
e.clear();
if(num==0)
{
for(int i=0;i<26;i++)if(vis[i]){path(i,0);break;}
}
else
{
for(int i=0;i<26;i++)
{
if(nd[i].out>nd[i].in){path(i,0);break;}
}
}
for(int i=e.size()-1;i>=0;i--)
{
if(i)cout<<e[i].s<<'.';
else cout<<e[i].s<<endl;
}
}
return 0;
}