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
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 }