【洛谷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;
}

猜你喜欢

转载自blog.csdn.net/chenxiaoran666/article/details/81274007
今日推荐