【洛谷1341】无序字母对(欧拉回路)
大致题意:给你\(n\)个各不相同的无序字母对(注意:两个字母可能相同,被这个坑了好几次),请构造一个长度为\(n+1\)的字符串包含每个字母对。
欧拉回路
这是一道裸的欧拉回路,只不过是字符串版的,步骤较经典版略显麻烦。
依照欧拉回路的思路,我们先统计出每个字母出现的次数。然后对其中奇点的个数分类讨论:
若没有奇点:则可以从任意一个点开始遍历。由于题目中要求字典序最小,所以从字典序最小的点开始遍历。
若有两个奇点:则可以从任意一个奇点开始遍历。由于题目中要求字典序最小,所以从字典序较小的奇点开始遍历。
若以上两种情况皆不满足:说明无解,输出“No Solution”。
代码
#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define LL long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define N ('z'-'A'+1)
using namespace std;
int n,ee=0,cnt=0,In[N+5],f[N+5][N+5],ans[100000];
inline void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline void dfs(int x)//dfs跑一遍欧拉回路
{
for(register int i=1;i+'A'-1<='z';++i)
if(f[x][i]) f[x][i]=f[i][x]=0,dfs(i);//将每一个能到达的字母按字典序一一遍历,并将连接当前字母与要到达的字母间的边删去
ans[++cnt]=x;//统计答案
}
int main()
{
register int i,j;char x,y,Min=0;
for(scanf("%d",&n),i=1;i<=n;++i) cin>>x>>y,f[x-'A'+1][y-'A'+1]=f[y-'A'+1][x-'A'+1]=1,++In[x-'A'+1],++In[y-'A'+1],Min=Min?min(Min,min(x,y)):min(x,y);//更新每个字母的入度,并记录字典序最小的字母,为没有奇点的情况做准备
int flag=0,t=0;//flag记录奇点的个数,t记录较小的奇点
for(i=1;i<=N;++i) if(In[i]&1) ++flag,t=t?min(t,i):i;//更新较小的奇点
if(flag&&flag^2) return puts("No Solution"),0;//如果奇点的个数不为0且不为2,就输出"No Solution"
for(dfs(flag?t:(Min-'A'+1)),i=cnt;i>0;--i) putchar(ans[i]+'A'-1);//尽量从字典序小的点跑一遍欧拉回路,并倒着输出答案
return 0;
}
待到再迷茫时回头望,所有脚印会发出光芒