题意:给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;
}