题意:给n个珠子,每个珠子有2种颜色,把所有珠子连成一个环,连接规则是2个珠子的连接处颜色必须相同,每种颜色用数字表示
理解:直接联想哈密顿回路,不科学,写不来。联想之前做的单词那个题(点击打开链接,这个讲的比较详细),然后果断欧拉回路,只不过那个是有向图,这个是无向图,并且输出路径。
方便看我还是贴出来吧
欧拉回路 图中经过每条边一次并且仅一次的回路称作欧拉回路。
欧拉路径 图中经过每条边一次并且仅一次的路径称作欧拉路径。
欧拉图 存在欧拉回路的图称为欧拉图。
半欧拉图 存在欧拉路径但不存在欧拉回路的图称为半欧拉图。
且存在顶点的入度比出度大1(终点)、的入度比出度小1(起点),其它所有顶点的入度等于出度。
怎么建图和判断欧拉回路都写在那个链接里面的。这次主要讲路径的输出。
后面写的所有内容都是在这个图(无向图)存在欧拉回路这个大前提下进行的
在网上看了些别人题解里面对于路径输出的题解,都是dfs遍历完所有边然后逆序存路径并输出。
一直想不通为什么要逆序,看了别人用PPT模拟了一个路径(点击打开链接),然后另外用其他点也进行了模拟下,就懂了
对一个点进行dfs的时候,假如这个点的度为2,那么从这个点出发必定会回到这个点(这个点即是起点也是终点,所以一边为起始边,另一边为终点边),如果回到这个点但是图中还有很多边,那么这条边就不能算最后一条边,必须把其他边都遍历完才能将这条边算作最后一条边。这样就证明正向dfs是错误的。
那为什么逆序是对的,dfs到一个点,这个点的度数减少为0,之前肯定也从这个点发出过一条边(大前提已说明有欧拉回路),那么从这条边也一定能回到之前的那条路,这样反过来把这一条边当成出发的第一条边反着走回去,一定能有序的回到之前的那条边。打个比方,就是你走路,往前走可以选择各个方向,那么倒着走之前走过的路是不是就是固定的路线了,且一定能回到起点。
然后这道题做法就是首先判断图是否连通,再判断是否存在欧拉回路,最后就是输出路径的问题了。
CODE
#include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> using namespace std; const int N = 55; int n; int E[N][N]; ///存边 int fa[N]; ///并查集判连通 int du[N]; ///每个点的度 bool vis[N]; ///标记这个点是否被访问 void Init() ///初始化 { for(int i = 0;i < N;i++) { fa[i] = i; du[i] = 0; vis[i] = false; for(int j = 0;j < N;j++) { E[i][j] = 0; } } } int Find(int x) { if(fa[x] != x) return fa[x] = Find(fa[x]); return fa[x]; } void Union(int x,int y) { int tx = Find(x); int ty = Find(y); fa[ty] = tx; } void dfs(int st) ///dfs找路径 { for(int i = 1;i <= 50;i++) { if(E[st][i]) { E[st][i]--; E[i][st]--; dfs(i); ///先走再输出 printf("%d %d\n",i,st); } } } int main(void) { int T; scanf("%d",&T); int cas = 1; while(T--) { Init(); scanf("%d",&n); for(int i = 1;i <= n;i++) { int a,b; scanf("%d%d",&a,&b); E[a][b]++; E[b][a]++; du[a]++; du[b]++; vis[a] = true; vis[b] = true; Union(a,b); ///无向图必须这样写成Union } int cnt_root = 0; ///根节点个数 for(int i = 1;i <= 50;i++) { if(vis[i] && fa[i] == i) cnt_root++; } printf("Case #%d\n",cas++); if(cnt_root > 1) ///用来作根节点的个数有1个以上说明不是连通图 { printf("some beads may be lost\n"); continue; } int flag = false; for(int i = 1;i <= 50;i++) { if(vis[i] && du[i]%2 == 1) ///点的度数为奇数说明不是欧拉回路 flag = true; } if(flag) { printf("some beads may be lost\n"); } else { for(int i = 1;i <= 50;i++) { if(vis[i]) { dfs(i); break; } } } if(T > 0) puts(""); ///TM这里没写返回WA你敢信 } return 0; }