You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

##AcWing 1124. 骑马修栅栏

一、题目描述

农民John每年有很多栅栏要修理。

他总是骑着马穿过每一个栅栏并修复它破损的地方。

John是一个与其他农民一样懒的人。

他讨厌骑马,因此 从来不两次经过一个栅栏(一笔画)。

你必须编一个程序,读入栅栏网络的描述,并计算出一条修栅栏的路径,使每个栅栏都恰好被经过一次

John从任何一个顶点(即两个栅栏的交点)开始骑马,在任意一个顶点结束(无向图求欧拉路径)。

每一个栅栏连接两个顶点,顶点用 1500 标号(虽然有的农场并没有 500 个顶点)。

一个顶点上可连接任意多( ≥1 )个栅栏。

所有栅栏 都是连通(不用判连通性) 的(也就是你可以从任意一个栅栏到达另外的所有栅栏)。

你的程序必须输出骑马的路径(用路上依次经过的顶点号码表示)。

我们如果把输出的路径看成是一个500进制的数,那么当存在多组解的情况下,输出500进制表示法中 最小 的一个 (也就是输出第一个数较小的,如果还有多组解,输出第二个数较小的,等等, 就说是字典序就完了)。

输入数据保证至少有一个解。

输入格式1 行:一个整数 F,表示栅栏的数目;

2F+1 行:每行两个整数 i,j 表示这条栅栏连接 ij 号顶点。

输出格式 输出应当有 F+1 行,每行一个整数,依次表示路径经过的顶点号。

注意数据可能有多组解,但是只有上面题目要求的那一组解是认为正确的。

数据范围 1≤F≤1024,1≤i,j≤500

输入样例

9
1 2
2 3
3 4
4 2
4 5
2 5
5 6
5 7
4 6

输出样例

1
2
3
4
2
5
4
6
5
7

二、解题思路

  • 稠密图,小图,可以用邻接矩阵存储,使用邻接矩阵存储,删边求欧拉路径时方便快捷
  • 要求输出 最小字典序,我们需要保证由 小点出发,一路上从小枚举到大
  • 无向图求欧拉路径的模板

步骤

  • 无向图:存在欧拉路径则所有点(除起点和终点)都是偶数点;欧拉回路:起点和终点也是偶数点
  • 先找一个有边的点,再看看有没有奇数点
  • 因为数据保证一定存在欧拉路径,所以如果不存在奇数点,则一定是欧拉回路

Code

#include <bits/stdc++.h>
using namespace std;

const int N = 510, M = N * N;

int n = 500, m;  // n个点m条边
int g[N][N];     // 邻接矩阵存图
int ans[M], cnt; // 路径
int d[N];        // 度

void dfs(int u) {
    // 因为最后的欧拉路径的序列是ans数组逆序
    // 节点u只有在遍历完所有边之后最后才会加到ans数组里面所以逆序过来就是最小的字典序
    for (int i = 1; i <= n; i++)
        if (g[u][i]) {
            // 删边优化
            g[u][i]--, g[i][u]--;
            dfs(i);
        }
    ans[++cnt] = u;
}

int main() {
    scanf("%d", &m);
    while (m--) {
        int a, b;
        scanf("%d %d", &a, &b);
        g[a][b]++, g[b][a]++; // 无向边,可记录重边
        d[a]++, d[b]++;       // 记录度
    }

    // 找起点
    int u = 0;
    // ① 从小到大,找到度为奇数的点,在无向图中,度为奇数的点,视为起点
    for (int i = 1; i <= n; i++)
        if (d[i] & 1) {
            u = i;
            break;
        }

    // ② 如果没有找到度为奇数的点,可能就是一个环,也就是欧拉回路
    if (!u)
        while (!d[u]) u++;

    dfs(u);

    for (int i = cnt; i; i--) printf("%d\n", ans[i]);

    return 0;
}