题目分析:1.无向图欧拉回路是否连通2.所有点的度为偶数。并查集+degree
这题题目保证了是联通的 所以就不用判断是否联通了
#include <iostream> #include <cstdio> #include <sstream> #include <cstring> #include <map> #include <set> #include <vector> #include <stack> #include <queue> #include <algorithm> #include <cmath> #define rap(a, n) for(int i=a; i<=n; i++) #define MOD 2018 #define LL long long #define ULL unsigned long long #define Pair pair<int, int> #define mem(a, b) memset(a, b, sizeof(a)) #define _ ios_base::sync_with_stdio(0),cin.tie(0) //freopen("1.txt", "r", stdin); using namespace std; const int maxn = 110, INF = 0x7fffffff; int n; int drgee[maxn], f[maxn], line[maxn][maxn]; //int find(int x) //{ // return f[x]==x?x:(f[x]=find(f[x])); //} void print(int u) { for(int i=1; i<=50; i++) if(line[u][i]) { line[u][i]--; line[i][u]--; print(i); printf("%d %d\n", i, u); } } int main() { int T, cnt, kase = 0; scanf("%d", &T); while(T--) { cnt = 0; mem(drgee, 0); mem(line, 0); // rap(1, maxn-1) f[i] = i; scanf("%d", &n); rap(1, n) { int u, v; scanf("%d%d", &u, &v); drgee[u]++; drgee[v]++; line[u][v]++; line[v][u]++; // f[u] = v; } printf("Case #%d\n", ++kase); // rap(1, n) // { // if(f[i] == i) // { // cnt++; // break; // } // } // if(cnt > 1) // { // cout<< "some beads may be lost" <<endl; // if(T) printf("\n"); // continue; // } cnt = 0; rap(1, 50) { if(drgee[i] & 1) { cnt++; break; } } if(cnt > 0) { printf("some beads may be lost\n"); if(T) printf("\n"); continue; } rap(1, 50) { print(i); } if(T) printf("\n"); } return 0; }
以下解释 转载至 https://www.cnblogs.com/scau20110726/archive/2012/11/09/2762371.html 文章 和 评论部分
如果写成这样是错的
void euler(int u) { int v; for(v=1; v<=50; v++) if(g[u][v]) { g[u][v]--; g[v][u]--;
printf("%d %d\n",u,v);
euler(v);
//这样相当于顺序输出 } }
在输入的时候使会有重边的,也就是g[i][j]的值不一定只是为1
然后从一个点出发,找到和他相连的点,然后删除这条无向边,所以是 g[u][v]--; g[v][u]--; 然后就去dfs下一个点v,最后在递归返回的时候才输出路径,也就是逆序输出,为什么要逆序输出了
因为和当前点i相连的点可能不止一个
例如当前点是1,上一条边是(3,1) . 而和1相连的点有2,7,11,能分成3个方向
往2的方向有:(1,2) (2,4)
往7的方向有:(1,7)(7,5)(5,6)
往11的方向有:(1,11)(11,12)(12,13)
如果顺序输出将会是
3 1
1 2
2 4
1 7
7 5
5 6
1 11
11 12
12 13
当找到起点之后,将起点压入栈中,然后访问与顶点相连的一个顶点,将该顶点压入栈中,同时删除这条边,然后继续DFS寻找顶点,并同样压栈、删除,最后,直到走到一个没有任何边与它相连的顶点(可能是起始点,也可能不是),便开始进行回溯,(回溯的同时进行弹栈,弹栈的结果也就是欧拉回路的逆序输出结果),回溯的过程就是寻找相连路径的过程,如果回溯的过程中发现仍然有边与当前顶点相连,那么继续从这个顶点沿着未删除的边去DFS,同时进行压栈等一系列操作,最后,必定会回到该点,然后继续回溯,直到顶点,逆序输出,结束
顺序输出如果要得到正确答案,则必须保证dfs不会回溯,即一条直线深入,到直线的最后全部边已经都访问完了。
假设要搜索的路径是:1->2->1,这种时候顺序输出是没有问题的,因为它只有一条路径的选择。
但如果在路径中间再加一个小环(对欧拉回路并不影响),变成这样:
1->2->(3->2)->1,这个时候就有可能要回溯了,如果顺序输出,结果可能会变成:
1 2
2 1
2 3(开始回溯)
3 2
当然顺序输出也有一定的几率会正确,但不能得到保证:
1 2
2 3(先搜索小环)
3 2(结束小环,回到正轨)
2 1
而逆序输出是在弹栈的时候输出的,任意的搜索顺序下都可以确保小环在主线内容全部输出完之前得到输出的机会。