P1341 无序字母对 欧拉路径
题目:P1341 无序字母对
题目描述
给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。
输入输出格式
输入格式:
第一行输入一个正整数n。
以下n行每行两个字母,表示这两个字母需要相邻。
输出格式:
输出满足要求的字符串。
如果没有满足要求的字符串,请输出“No Solution”。
如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案
要求:构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。
题解:将每个字母看成一个点,每对字母看成一条边,题目要求就变成了,找到一条路径,使其能经过所有边并且每条边只走一次(保证了只有n+1个字母),题目很明显变成了一个求欧拉路径的题。
欧拉回路:奇数度的点为0;欧拉路径:奇数点的度为2;
#include<bits/stdc++.h>
using namespace std;
int n;
vector<int > g[130];
int du[130]={0};
int st=130;
int ans=0;
int vis[130][130]={0};
int path[2000];
int k=0;
void dfs(int i){
for(int j=0;j<g[i].size();j++){
int a=g[i][j];
if(!vis[i][a]){//找到第一个未走过的路,字典序最小
vis[i][a]=vis[a][i]=1;//标记路走过
dfs(a);
}
}
path[++k]=i;//记录路径
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
cin>>n;
char a[2];
for(int i=0;i<n;i++){
cin>>a;
du[a[0]]++,du[a[1]]++;//记录每个节点的度
g[a[0]].push_back(a[1]);
g[a[1]].push_back(a[0]);
}
for(int i=65;i<130;i++) sort(g[i].begin(),g[i].end());//将每个点连接边的终点 按字典序排序
for(int i=65;i<130;i++){
if(du[i]%2==1){
if(!ans)st=i;//第一个奇数点为字典序最小的点,起点
ans++;//奇数点个数
}
}
//奇数点为2则存在欧拉路径,奇数点为0则存在欧拉回路
if(ans!=0&&ans!=2){
cout<<"No Solution"<<endl;
return 0;
}
if(!ans){//是欧拉回路,则需要再找起点
for(int i=65;i<130;i++){
if(du[i]) { st=i; break;}
}
}
dfs(st);//深搜起点,找到路径
for(int i=k;i>=0;i--){//逆序输出
cout<<(char)path[i];
}
cout<<endl;
return 0;
}