「USACO」「LuoguP2731」 骑马修栅栏 Riding the Fences(欧拉路径

Description

Farmer John每年有很多栅栏要修理。他总是骑着马穿过每一个栅栏并修复它破损的地方。

John是一个与其他农民一样懒的人。他讨厌骑马,因此从来不两次经过一个栅栏。你必须编一个程序,读入栅栏网络的描述,并计算出一条修栅栏的路径,使每个栅栏都恰好被经过一次。John能从任何一个顶点(即两个栅栏的交点)开始骑马,在任意一个顶点结束。

每一个栅栏连接两个顶点,顶点用1到500标号(虽然有的农场并没有500个顶点)。一个顶点上可连接任意多(>=1)个栅栏。两顶点间可能有多个栅栏。所有栅栏都是连通的(也就是你可以从任意一个栅栏到达另外的所有栅栏)。

你的程序必须输出骑马的路径(用路上依次经过的顶点号码表示)。我们如果把输出的路径看成是一个500进制的数,那么当存在多组解的情况下,输出500进制表示法中最小的一个 (也就是输出第一位较小的,如果还有多组解,输出第二位较小的,等等)。

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

Input

第1行: 一个整数F(1 <= F <= 1024),表示栅栏的数目

第2到F+1行: 每行两个整数i, j(1 <= i,j <= 500)表示这条栅栏连接i与j号顶点。

Output

输出应当有F+1行,每行一个整数,依次表示路径经过的顶点号。注意数据可能有多组解,但是只有上面题目要求的那一组解是认为正确的。

Sample Input

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

Sample Output

1
2
3
4
2
5
4
6
5
7

说明

题目翻译来自NOCOW。

USACO Training Section 3.3

题解

欧拉路径的模板题了吧

预备知识:

欧拉回路:从一个点可以遍历整张图,最后回到原来的点

欧拉通路:从一个点可以遍历整张图,最后回不到原来的点

对于无向图而言:(大前提:图联通

欧拉回路:任意点的度数为偶 起点可随意

欧拉通路:有且仅有两个点度数为奇 在遍历时一定要从一个为奇的点到另一个为奇的点

对于有向图:(还是大前提图联通

欧拉回路:每个点入度==出度

欧拉通路:有且仅有一个点出度-入度==1 为起点;有且仅有一个点入度-出度==1 为终点; 其余的点出度==入度

然后这道题的解法和算法学习都借鉴了排名第一的题解Misaka_Azusa的题解

所以是Hierholzers算法啦!

双向存边,记录每个点的度。

从小到大扫一遍  找有没有度数为奇的点 若有则break,从当前点开始dfs(欧拉通路

如果所有点度为偶则从最小的点开始dfs(欧拉回路

 1 stack<int>st;
 2 void dfs(int x)
 3 {
 4     for(int v=l;v<=r;++v)
 5     if(tu[x][v])
 6     {
 7         tu[x][v]--;
 8         tu[v][x]--;
 9         dfs(v);
10     }
11     st.push(x);
12     return;
13 }

看代码然后强行理解应该就够了

然后对于stack 一开始自作聪明的成在开头直接输出QAQ

如果有一样的危险想法,讨论区给的这个样例还是蛮助于理解的

1 6 
2 1 2 
3 2 3 
4 3 4 
5 3 5 
6 3 6 
7 5 6 
View Code

以下是全代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<stack>
 4 #include<cmath>
 5 using namespace std;
 6 int du[507];
 7 int tu[507][507];
 8 int l,r;
 9 stack<int>st;
10 void dfs(int x)
11 {
12     for(int v=l;v<=r;++v)
13     if(tu[x][v])
14     {
15         tu[x][v]--;
16         tu[v][x]--;
17         dfs(v);
18     }
19     st.push(x);
20     return;
21 }
22 int main()
23 {
24     int f;
25     scanf("%d",&f);
26     l=9999,r=0;
27     for(int i=1;i<=f;++i)
28     {
29         int x,y;
30         scanf("%d%d",&x,&y);
31         tu[x][y]++;
32         tu[y][x]++;
33         du[x]++;
34         du[y]++;
35         l=min(l,x);
36         l=min(l,y);
37         r=max(r,x);
38         r=max(r,y);
39     }
40     int s=l;
41     for(int i=l;i<=r;++i)
42     if(du[i]%2==1){s=i;break;}
43     dfs(s);
44     while(!st.empty())
45     {
46         printf("%d
",st.top());
47         st.pop();
48     }
49     return 0;
50 }
View Code

YJQ说这是集训队算法(逃

原文地址:https://www.cnblogs.com/qwerta/p/9383588.html