题目来源:http://poj.org/problem?id=1041
题目大意:
John有很多朋友住在不同的街,John想去访问每位朋友,同时希望走的路最少。因为道路很窄,John在一条路上不能往回走。John希望从家里出发,拜访完所有的朋友后回到自己的家,且总的路程最短。John意识到如果可以每条道路都只走一次然后返回起点应该是最短的路径。写一个程序帮助John找到这样的路径。给出的每条街连接两个路口,最多有1995条街,最多44个路口。街编号由1到n, 路口分别编号1到m.
输入:每个用例一个数据块:每行表示一条街,由三个整数组成:x,y,z. z为这条街的编号,x和y表示这条街连接的两个路口的编号。(实际数据中可能是自环).John住在一个输入块中第一行中连接的两个顶点中编号较小的路口处。所有的街都可以连通到其他街上。“0 0”表示一个数据块的结束。再一个0 0 表示输入的结束。
输出:如果能找到所有街道遍历一次的回路,输出找到的路径,如果不存在,输出“Round trip does not exist.”
Sample Input
1 2 1 2 3 2 3 1 6 1 2 5 2 3 3 3 1 4 0 0 1 2 1 2 3 2 1 3 3 2 4 4 0 0 0 0
Sample Output
1 2 3 5 4 6 Round trip does not exist.
题目一看就似曾相识,原来是著名的欧拉回路。
欧拉回路定义:图G的一个回路,若它恰通过G中每条边一次,则称该回路为欧拉(Euler)回路。
一开始直接用DFS,结果超时,后来看到欧拉回路存在的充要条件:
无向图:是连通图且所有顶点的度为偶数。
有向图:是连通图且所有顶点的入度等于出度。
题目中的是无向图,且保证了图的连通性,所以只要判断顶点的度数是否为偶数即可。确定存在欧拉回路再用dfs搜索就一定能找到了。
图中可能存在重边,数据结构的选择比较重要。代码中的map[i][j]表示表示由顶点i经街道j到达的顶点编号。
1 ////////////////////////////////////////////////////////////////////////// 2 // POJ1041 John's trip 3 // result: Memory: 540K Time: 47MS 4 // Language: C++ Result: Accepted 5 ////////////////////////////////////////////////////////////////////////// 6 7 #include <cstdio> 8 #include <iostream> 9 10 using namespace std; 11 int street_cnt; 12 int street[1996][2]; 13 bool visited[1996]; 14 int map[45][1995]; //map[i][j]表示由顶点i经街道j会到达的顶点编号 15 int degree[45]; 16 int stack[1995]; 17 int stack_top; 18 int home; 19 20 inline void record(int &x, int &y, int &z) { 21 street[z][0] = x; 22 street[z][1] = y; 23 map[x][z] = y; 24 map[y][z] = x; 25 ++degree[x]; 26 ++degree[y]; 27 } 28 29 void dfs(int j) { 30 for (int i = 1; i <= street_cnt; ++i) { 31 if (!visited[i] && map[j][i]) { 32 visited[i] = true; 33 dfs(map[j][i]); 34 stack[stack_top++] = i; 35 } 36 } 37 } 38 39 int main(void) { 40 while (true) { 41 int x, y, z; 42 scanf("%d%d", &x, &y); 43 if (x == 0 && y == 0) { 44 break; 45 } 46 scanf("%d", &z); 47 memset(map, false, sizeof(map)); 48 memset(degree, 0, sizeof(degree)); 49 record(x, y, z); 50 home = x < y ? x : y; 51 street_cnt = 1; 52 while (true) { 53 scanf("%d%d", &x, &y); 54 if (x == 0 && y == 0) { 55 break; 56 } 57 scanf("%d", &z); 58 record(x, y, z); 59 ++street_cnt; 60 } 61 bool flag = true; 62 //欧拉回路存在的充要条件是每个顶点的度数都为偶数 63 for (int i = 1; i <= 44; ++i) { 64 if (degree[i] % 2 != 0) { 65 flag = false; 66 break; 67 } 68 } 69 if (flag == false) { 70 printf("Round trip does not exist. "); 71 continue; 72 } 73 memset(visited, false, sizeof(visited)); 74 stack_top = 0; 75 dfs(home); 76 for (int i = stack_top - 1; i > 0; --i) { 77 printf("%d ", stack[i]); 78 } 79 printf("%d ", stack[0]); 80 } 81 return 0; 82 }