欧拉图 洛谷P1341 无序字母对

题目链接:https://www.luogu.org/problem/P1341

题意:给你n个无序对(位置可以颠倒),但必须相邻,问能否构造一个长为n+1的字符串,使得包含每个无序对,如果可以,输出字典序最小的字符串

分析:必须包含每个无序对,每个无序对必须相邻,我们可以抽象为图论问题,无序对间连一个无向边,那么问题就转化为一笔画问题了

即能不能在图中找到一个欧拉回路或者欧拉通路

注:欧拉通路:经过图上的每一条边

一开始要先用并查集判断是否联通

无向图判断欧拉回路:度数全为偶数

无向图判断欧拉通路:除了两点为奇数,其余度数全为偶数,存在以该两点为起始点的欧拉通路

有向图判断欧拉通路:入度等于出度

有向图判断欧拉回路:最多有一点入度等于出度+1,最多有一点入度等于出度-1,就会有一条从出度大于入度(没有则等于)的点出发,到达出度小于入度(没有则等于)的点的一条欧拉路径。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll mod=1000000007;
const int maxn=1e5+7;
int mp[200][200];
char in[2];
int du[200],fa[200];//分别用来存储度数和父亲 
int n;
char ans[3000];
int find(int x){
    if(x!=fa[x]) return fa[x]=find(fa[x]);
    return x;
}
void dfs(int x){
    for(int i=65;i<=122;i++){
        if(mp[x][i]){
            mp[x][i]=0;
            mp[i][x]=0;
            dfs(i);
        }
    }
    ans[n--]=x;//因为是回溯的时候加值,故倒着存 
}
int main(){
    //A的编码为65,z的为122 
    for(int i=65;i<=122;i++)fa[i]=i;//并查集基操
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",in);
        mp[in[0]][in[1]]=1;
        mp[in[1]][in[0]]=1;
        du[in[0]]++,du[in[1]]++;
        int x=find(in[0]),y=find(in[1]);
        fa[x]=y;
    }
    int num=0;
    for(int i=65;i<=122;i++)
        if(i==fa[i]&&du[i]) num++;//判断是否只有一个连通分量即连通
    if(num!=1){
        printf("No Solution\n");
        return 0;
    } 
    num=0;
    int s=0;//标记起点,如果存在欧拉回路就是字典序最小的,如果存在欧拉通路就是两点先出现的那个(字典序更小)
    for(int i=65;i<=122;i++){
        if(du[i]%2){//度数为奇数的点个数记录下来 
            num++;
            if(s==0) s=i;
        }
    }
    if(num&&num!=2){//既无欧拉通路也无欧拉回路 
        printf("No Solution\n");
        return 0;
    }
    if(num==0){//有欧拉回路 
        for(int i=65;i<=122;i++){
            if(du[i]){
                s=i;
                break;
            }
        }
    }
    dfs(s);
    printf("%s\n",ans); 
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/qingjiuling/p/11512014.html