题目地址:
https://www.luogu.com.cn/problem/P2731
题目背景:
Farmer John每年有很多栅栏要修理。他总是骑着马穿过每一个栅栏并修复它破损的地方。
题目描述:
John是一个与其他农民一样懒的人。他讨厌骑马,因此从来不两次经过一个栅栏。John的农场上一共有
m
m
m个栅栏,每一个栅栏连接两个顶点,顶点用
1
1
1到
500
500
500标号(虽然有的农场并没有那么多个顶点)。一个顶点上至少连接
1
1
1个栅栏,没有上限。两顶点间可能有多个栅栏。所有栅栏都是连通的(也就是你可以从任意一个栅栏到达另外的所有栅栏)。John能从任何一个顶点(即两个栅栏的交点)开始骑马,在任意一个顶点结束。你需要求出输出骑马的路径(用路上依次经过的顶点号码表示),使每个栅栏都恰好被经过一次。如果存在多组可行的解,按照如下方式进行输出:如果把输出的路径看成是一个
500
500
500进制的数,那么当存在多组解的情况下,输出
500
500
500进制表示法中最小的一个 (也就是输出第一位较小的,如果还有多组解,输出第二位较小的,以此类推)。输入数据保证至少有一个解。
输入格式:
第一行一个整数
m
m
m,表示栅栏的数目。从第二行到第
m
+
1
m+1
m+1行,每行两个整数
u
,
v
u,v
u,v,表示有一条栅栏连接
u
,
v
u,v
u,v两个点。
输出格式:
共
m
+
1
m+1
m+1行,每行一个整数,依次表示路径经过的顶点号。注意数据可能有多组解,但是只有上面题目要求的那一组解是认为正确的。数据保证至少有一组可行解。
数据范围:
对于
100
%
100\%
100%的数据,
1
≤
m
≤
1024
,
1
≤
u
,
v
≤
500
1≤m≤1024,1≤u,v≤500
1≤m≤1024,1≤u,v≤500。
欧拉路径问题。先判断是否存在欧拉路径(如果是欧拉回路,则每个点度数都为偶数,从 1 1 1号点出发;否则找到第 1 1 1个度数为奇数的点,该点即为起点),然后DFS一遍即可。代码如下:
#include <iostream>
using namespace std;
const int N = 510, M = 1024 << 1;
int n, m;
int g[N][N], d[N];
int res[(M >> 1) + 10], cnt;
void dfs(int u) {
for (int i = 1; i <= n; i++)
if (g[u][i]) {
g[u][i]--;
g[i][u]--;
dfs(i);
}
res[cnt++] = u;
}
int main() {
scanf("%d", &m);
while (m--) {
int a, b;
scanf("%d%d", &a, &b);
g[a][b]++;
g[b][a]++;
d[b]++;
d[a]++;
n = max(n, max(a, b));
}
int S = 1;
for (int i = 1; i <= n; i++)
if (d[i] & 1) {
S = i;
break;
}
dfs(S);
for (int i = cnt - 1; i >= 0; i--)
printf("%d\n", res[i]);
}
时间复杂度 O ( m n ) O(mn) O(mn),空间 O ( n ) O(n) O(n)。