POJ1041 John's trip 【字典序输出欧拉回路】

题目链接:http://poj.org/problem?id=1041

题目大意:给出一个连通图,判断是否存在欧拉回路,若存在输出一条字典序最小的路径。

我的想法:

1.一开始我是用结构体记录边的起点终点以及边的序号,然后将序号按照从小到大排序。再用链式前向星来存以及排好序的边,然后dfs从小到大遍历。但是错了,原因是链式前向星遍历边是反向遍历的,并且并没有将边的序号一一对应上。

正确思路:

1.首先要明白欧拉回路存在的条件。一.连通图(可以用并查集或者tarjan来判断是否连通)。二.无向图每个点的度为偶数,有向图每个点的入度等于出度。所以在判断欧拉回路之前要先判连通以及度。

2.这道题的关键在于数据结构的选择,我用结构体+链式前向星就不行。仔细思考输出边序号的字典序最小,那我们就可以用 G[][]二维数组来表示,G[A][B] = C表示A点通过B边与C相连。这样就可以在dfs中从小到大for一遍B来保证优先选择序号小的边。

3.dfs中利用栈S,在回溯的过程中将路径压入栈中。若此时路径不符合,则代表此次回溯经过的路径应该是在其他路径后面经过的,正好符合栈的输出特点。例如:1-2-3-4-5-6路径回溯时入栈顺序为6-5-4-3-2-1,最后出栈就为1-2-3-4-5-6.正确。

代码里有注释

代码:

注意:因为题目已经说明了保证给出的图是一个连通图,所以这里没有判连通。

注意:数据有问题,数组要开大点,否则会WA

POJ1041 John's trip 【字典序输出欧拉回路】
 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #include<stack>
 5 #define mem(a, b) memset(a, b, sizeof(a))
 6 using namespace std;
 7 
 8 int a, b, c, flag;
 9 int du[2000], vis[5000];
10 int G[2000][5000]; //关键数组,G[a][b] = c表示a点通过b边与c相连 
11 int maxm, maxn;
12 stack<int>S;
13 
14 void init()
15 {
16     mem(du, 0);
17     mem(G, 0);
18     mem(vis, 0);
19     maxm = -1;
20     flag = 1;
21     while(!S.empty())
22         S.pop();
23 }
24 
25 void dfs(int now)
26 {
27     for(int i = 1; i <= maxm; i ++)  //每次dfs都从小的边开始,保证字典序 
28     {
29         if(vis[i] || G[now][i] == 0)//若没有边或者已经走过了 
30             continue;
31         vis[i] = 1;
32         dfs(G[now][i]);
33         S.push(i);//回溯过程中将边入栈,最后倒序输出,若一次走不完,那么回溯完找其他路径,这些路径会被压到栈下面,也表示后面再走 
34     }
35 }
36 
37 int main()
38 {
39     while(scanf("%d%d", &a, &b) != EOF)
40     {
41         if(a == 0 && b == 0)
42             break;
43         init();
44         scanf("%d", &c);
45         du[a] ++, du[b] ++;//度数 
46         G[a][c] = b, G[b][c] = a;
47         maxm = max(maxm, c);//边数 
48         maxn = max(a, b);//点数 
49         while(1)
50         {
51             scanf("%d%d", &a, &b);
52             if(a == 0 && b == 0)
53                 break;
54             scanf("%d", &c);
55             du[a] ++, du[b] ++;
56             G[a][c] = b, G[b][c] = a;
57             maxm = max(maxm, c);
58             maxn = max(maxn, max(a, b));
59         }
60         for(int i = 1; i <= maxn; i ++)
61             if(du[i] % 2)
62             {
63                 flag = 0;
64                 break;
65             }
66         if(!flag)
67         {
68             printf("Round trip does not exist.\n");
69             continue;
70         }
71         dfs(1);
72         printf("%d", S.top());
73         S.pop();
74         while(!S.empty())
75         {
76              printf(" %d", S.top());
77              S.pop();
78         }
79         printf("\n");
80     }
81     return 0;
82 }
POJ1041

 

上一篇:彻底理解javascript中的this指针


下一篇:POJ3278_Catch That Cow(JAVA语言)