1.Question:
描述
给你一些单词,请你判断能否把它们首尾串起来串成一串。
前一个单词的结尾应该与下一个单词的道字母相同。
如
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 ***
2.Solution:
本题如果处理不当的话,非常容易造成TLE
首先,本题我们需要对题目进行抽象
我们将每个单词看作是一条边,单词的首字符和尾字符看作是边的起点和终点,这里我们就可以抽象出一个有26个顶点的稠密图,因为题目声明了图的稠密程度达到了1005:26所以说,在这里邻接矩阵的存储思路已经不再适用,我们需要利用邻接表来存储
并且,题目声明了搜索的顺序是边(和顶点)的字典序输出,所以本题我们需要利用strcmp函数来辅助构建有顺序的邻接表
PS:本题TLE很可能是因为没有考虑很多的特殊情况
1.入度与出度相差大不止1,造成TLE
2.不考虑回路的问题造成TLE
3.本日我给每条边加上了lazy标记,防止我搜索的时候进行重复搜索从而出现TLE或者WA的情况
有向图存在欧拉通路的充分必要条件:
有向图中只存在两个点的出度和入度相差位1,且相差情况刚好相反,其他点的入度和出度相等
并且欧拉通路存在之时,我们的通路的起点必定是入度小的那个点,终点必定是出度少的那个点
3.Code:
#include"iostream"
#include"cstdio"
#include"cstring"
#include"cstdlib"
#define N 30
using namespace std;
typedef struct node
{
char data[32];
struct node* next;
bool lazy;
}point;
int t,n;
point head[30];
int in_degree[30];
int out_degree[30];
int begin,eend;
char s[1005][32];
int s_num=0;
void init()
{
begin=eend=0;
s_num=0;
for(int i=0;i<30;i++)
{
head[i].next=NULL;
}
memset(in_degree,0,sizeof(in_degree));
memset(out_degree,0,sizeof(out_degree));
return ;
}
bool dfs(int root)
{
if(s_num==n)
{
for(int i=0;i<n-1;i++)
{
printf("%s.",s[i]);
}
printf("%s\n",s[s_num-1]);
return true;
}
point* k=head[root].next;
while(k!=NULL)
{
if(k->lazy==1)
{
k=k->next;
continue;
}
k->lazy=1;
strcpy(s[s_num++],k->data);
bool judge=dfs(k->data[strlen(k->data)-1]-'a');
if(judge) return true;
s_num--;
k->lazy=0;
k=k->next;
}
return false;
}
int main()
{
char pp[32];
scanf("%d",&t);getchar();
while(t--)
{
init();
scanf("%d",&n);getchar();
for(int i=1;i<=n;i++)
{
scanf("%s",pp);
out_degree[pp[0]-'a']++;
in_degree[pp[strlen(pp)-1]-'a']++;
point* p=new point;
strcpy(p->data,pp);
p->next=NULL;
p->lazy=0;
point* w=&head[pp[0]-'a'];
while(w->next!=NULL&&strcmp(w->next->data,pp)<0)
{
w=w->next;
}
p->next=w->next;
w->next=p;
}
bool flag=1;
int number=0;
for(int i=0;i<30;i++)
{
if(in_degree[i]==out_degree[i]-1) begin=i;
else if(in_degree[i]==out_degree[i]+1) eend=i;
else
{
if(abs(in_degree[i]-out_degree[i])>=2)
{
flag=0;
printf("***\n");
break;
}
number--;
}
number++;
}
if(flag==0) continue;
if((number==0||number==2)&&dfs(begin));
else printf("***\n");
}
return 0;
}