洛谷 P1341 无序字母对 欧拉路

题目:https://www.luogu.org/problemnew/show/P1341

给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。

欧拉路相关知识:https://blog.csdn.net/chenxiaoran666/article/details/82533147

题解:

这里就可以发现实际上就是在找欧拉路,
首先每个字符就是代表的图中的某一个点,输入的字符串,就代表两点之间有连通,
构造字符串就是在找输出一笔画回路,明白这个代码就很简单了。
 

#include <cstdio>
#include <iostream>
using namespace std;
// 'z'=122 字母最大不超过122 //很奇怪,我填150+5,后面第#8 9 10,都RE了 TAT
const int maxn = 200 + 5; 
int n, ans;
int dis[maxn][maxn], depth[maxn]; // dis代表两点连接的数量,depth代表度数
char a[maxn];                     //存路径

void dfs(int i) { //深搜找欧拉路,i表示当前找的这个点
    for (int j = 1; j < maxn; j++) {
        if (dis[i][j]) { //如果两点之间有连通
            dis[i][j]--; //毁图大法
            dis[j][i]--;
            dfs(j);
        }
    }
    a[++ans] = i; //记录路径
    return;
}

int main() {
    // freopen("data.txt","r",stdin);
    string s;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> s;
        dis[s[0]]
           [s[1]]++; //记录路径,数组第一维表示当前的点,与第二维的点有连接
        dis[s[1]][s[0]]++;
        depth[s[0]]++; //记录度数
        depth[s[1]]++;
    }
    int cnt = 0, h = 0; //开始找点,//h,最开始找到的设置为起点,即为最小ASCLL码开始
    for (int i = 1; i < maxn; i++)
        if (depth[i] & 1) { //找度数为奇数的点,第一个置为起点
            cnt++;
            if (!h)
                h = i;
        }
    if (cnt && cnt != 2) { //没有奇点或者奇点数量不为2,就不形成一个欧拉路
        cout << "No Solution";
        return 0;
    }
    if (!h) //找不到奇点,就是另外找点(度数不为0的任意一点)
        for (int i = 1; i < maxn; i++)
            if (depth[i]) {
                h = i;
                break;
            }
    dfs(h);
    if (ans <
        n + 1) { //搜完以后判断一下,因为n组连边,必有n+1个点,前提是不重复
        cout << "No Solution";
        return 0;
    }
    for (int i = ans; i >= 1; i--) //倒叙输出,因为存点是深搜之后存的点
        cout << a[i];
    cout << endl;

    return 0;
}

题解来源:https://www.luogu.org/blog/41302/solution-p1341

猜你喜欢

转载自blog.csdn.net/qq_38861305/article/details/90209135