题目网站
题目描述
给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。
输入输出格式
输入格式:
第一行输入一个正整数n。
以下n行每行两个字母,表示这两个字母需要相邻。
输出格式:
输出满足要求的字符串。
如果没有满足要求的字符串,请输出“No Solution”。
如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案
输入输出样例
输入样例#1:
4
aZ
tZ
Xt
aX
输出样例#1:
XaZtX
说明
【数据规模与约定】
不同的无序字母对个数有限,n的规模可以通过计算得到。
1.看到本题的第一印象是很蒙的,因为这种题也不好模拟啊,深搜代码一开始也是十分不好打的,于是就开始去建立图
2.当想到去建立图之后,问题就很是明朗了,题目的意思难道不就是从一个字母出发,输入数据中每两个字母有一条路,在我们的结果中必须要将这条路遍历到,并且该图为无向图,也就是我们只需要找一条欧拉路径走完每一条边
3.那么何为欧拉路径(这里简单叙述一下)
欧拉路径就是:在一个图G中找到一条路劲经过每条边并且仅经过一次的路径
再来看本题,是否就是需要在一个无向图中找到一条欧拉路径,并且将路径输出
那如何判断是否存在欧拉路径:
在无向图中,下面两种情况都可以找到一条合法的欧拉路径
(度就是该点所连的边,被指向的为入度,反之为出度)
欧拉图(存在欧拉回路):该图是连通的且每个点的度数都是偶数
半欧拉图(存在欧拉路径):该图连通且仅有两个点的读数是奇数,这两个点即为欧拉路径的起始点
4.代码讲解
(1)解决输入及预处理问题
1. 这里直接使用二维数组进行存图,因为是无向图所以在存的时候要双向;
2.由3可知我们如果要判断是否无解,直接就判断该图是否为欧拉图或半欧拉图就好了,所以在输入的时候需要存度(无向图我们就不管入度 出度),然后遍历进行判定,如果有点的度不为偶数,且这样的点的个数不等于2,那么我们直接输出无解
(如果是二,就是一头一尾的半欧拉图)
3.同时又因为,在最后输出的时候要使字典序更小,所以我们在找开始点的时候,就从小开始找,符合条件的入手点,这里有个小问题。就是在我们找这个点的时候有可能会发生错误,下面为策略。首先,我们不知道该图是否是半欧拉图,所以一开始我们找到有度为基数的点,就将start赋值为该点。循环结束后,我们再判定start是否为零,如果为零,说明没有找到基数的点,再找到队列中字典序最小的点作为start就好。如果start不为0,就判定一共有几个基数点,如果不等于2直接return 0;,如果等于2,就以此作为起始点
4.这一段的代码如下
cin>>n;
char b,c;
for(int i=1;i<=n;i++)
{
cin>>b>>c;
a[b][c]++;
a[c][b]++;
du[c]++;
du[b]++;
}
int ans=0;
for(int i=0;i<=150;i++)
{
if(du[i]%2==1)
{
ans++;
if(!start) start=i;
}
}
if(!start)
{
for(int i=0;i<=150;i++)
{
if(du[i])
{
start=i;
break;
}
}
}
if(ans!=0&&ans!=2)
{
cout<<"No Solution"<<endl;
return 0;
}
(2)深搜求解
接下的步骤看似复杂,其实就是一个基础的深搜
从起点开始,从小到大一直找,找到有路就向下递归,再回溯时候赋值
void find (int k)
{
for(int i=0;i<=150;i++)//省事
{
if(a[k][i])//如果有路就搜
{
a[k][i]--;//遍历过的路就毁掉,保证只走一次
a[i][k]--;
dfs(i);
}
}
sum++;
op[sum]=k;
//这里需要注意的是,因为我们是深搜完成之后再进行的赋值,所以越后扫到的数越先入队,所以输出时倒序
return ;
}
(3)附上AC代码,上面片段代码已经很详细了,所以这段代码就没有过多注释了
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#define maxn 10005
using namespace std;
int n;
int start;
int du[maxn];
int a[maxn][maxn];
int flag=0;
char op[10050];
int sum=n+1;
void find (int now)
{
for(int i=0;i<=150;i++)
{
if(a[now][i])
{
a[now][i]--;
a[i][now]--;
find(i);
}
}
sum++;
op[sum]=now;
return ;
}
int main()
{
cin>>n;
char b,c;
for(int i=1;i<=n;i++)
{
cin>>b>>c;
a[b][c]++;
a[c][b]++;
du[c]++;
du[b]++;
}
int ans=0;
for(int i=0;i<=150;i++)
{
if(du[i]%2==1)
{
ans++;
if(!start) start=i;
}
}
if(!start)
{
for(int i=0;i<=150;i++)
{
if(du[i])
{
start=i;
break;
}
}
}
if(ans!=0&&ans!=2)
{
cout<<"No Solution"<<endl;
return 0;
}
find(start);
if(sum<n+1)
{
cout<<"No Solution"<<endl;
return 0;
}
for(int i=sum;i>=1;i--)
cout<<op[i];
return 0;
}