洛谷P1341 无序字母对 - 欧拉路/欧拉回路

判断欧拉路:图中只有两个度数为奇数的点,其余均为偶数
欧拉回路:图中所有点度数均为偶数
欧拉图:图是连通的并且存在欧拉回路

欧拉回路其实就是欧拉路的两头连了边

这道题可以把给出的字母对的两个字母连一下无向边(一开始我想的是把字母队首位可连的处理一下。。。但是果然太麻烦,输出也费事,常常一眼看错题意,当做法太麻烦时,考虑是不是想多了想错了,找找反例,说不定没往正解的路子上走)
需要注意的是A字典序小于a(至少从ascii码上是这样的)
然后把字符处理一下,因为大写和小写之间的ascii码查了几个字符,所以设1~26为大写字母,27~52为小写字母,这样映射起来方便
然后字典序最小,对于欧拉路来说两个端点取个小的作为起点,对于欧拉回路来说取一个最小的作为起点
但其实“每条边只走一次”在欧拉图中依然会有许多种走法,并不是简单地规定某一方向就能最小(应用到别的类型的题也一样,并不是我简单地规定前几次走路的方向就能找到最小走法了,以后多多注意这方面),求字典序最小的话,只需要从最小的起点开始,每次都往最小的点上走就可以了,所以每次直接暴力从小到大枚举字符(1~52),看哪个字符和当前有边,就走下去

需要注意的是,欧拉路不是乱走能走出来的,所以需要用栈来完成“拼接回路”的工作,具体我不会证明,但过程是当x的所有边都访问完毕时,x入栈,最后倒序输出栈中所有节点(或者说从栈中一个个弹出来)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 1000 + 10;
int n,e[60][60],du[MAXN],cnt,s=1<<30,sr=1<<30;
int pu[100000 + 10],tot;
string a,ans;
int tra(char x) {
    if(x>='a' && x<='z') {
        return x - 'a' + 27;
    } else {
        return x - 'A' + 1;
    }
}
char rt(int x) {
    char c;
    if(x>26) {
        c = x - 27 + 'a';
    } else c = x - 1 + 'A';
    return c;
}
void dfs(int x) {
    for(int i=1; i<=60; i++) {
        if(e[x][i]) {
            e[x][i] = e[i][x] = 0;
            dfs(i);
        }
    }
    pu[++tot] = x;
} 
int main() {
    cin>>n;
    for(int i=1; i<=n; i++) {
        cin >> a;
        int u = tra(a[0]), v = tra(a[1]);
        e[u][v] = e[v][u] = 1;
        du[u]++, du[v]++; 
    }
    for(int i=1; i<=60; i++) {
        if(du[i] % 2) {
            cnt++;
            s = min(s, i);
        }
        if(du[i]) sr = min(sr, i);
    }
    if(cnt != 0 && cnt != 2) {
        printf("No Solution");
    }
    if(cnt == 2) {
        dfs(s);
    }
    if(!cnt) {
        dfs(sr);
    }
    for(int i=tot; i; i--) {
        printf("%c", rt(pu[i]));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Fantasy_World/article/details/81706906