UVA10054欧拉回路

24 篇文章 0 订阅

解释下什么事欧拉回路,欧拉回路就是欧拉道路的进化版,

欧拉道路是存在俩个奇点,从一个奇点出发到另一个奇点,而欧拉回路是不存在奇点,

从任意点出发最终一定会回到该点。

无向图的欧拉回路判断和路径输出

1.判断所有的点的度是否为偶数,如果有点不为偶数,则不存在欧拉回路

2.满足1的条件下,判断所给的图是否连通,不连通也不是欧拉回路

3.满足1和2的就是欧拉回路,然后dfs逆序输出路径,主要一定要逆序,不逆序是错的,后面会解释


然而这题竟然不需要判断是否连通,然而我写了。

最重要的一点就是因为会有重边,所以输出的时候是G[u][i]--,G[i][u]--;

另外输出的时候必须逆序输出。

原因如下:

在输入的时候使会有重边的,也就是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

而逆序输出是在弹栈的时候输出的,任意的搜索顺序下都可以确保小环在主线内容全部输出完之前得到输出的机会

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#include<map>
#include<cctype>
#include<cmath>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#define LL long long
using namespace std;
const int N=55;
int n;
int G[N][N],deg[N];
int vis[N];
/*void dfs(int u)
{
    vis[u]=1;
    for(int i=0;i<N;i++)
        if(G[u][i]&&!vis[i])
        {
            dfs(i);
        }

}*/
void dfs2(int u)
{
    for(int i=0;i<N;i++)
        if(G[u][i])
    {
        G[u][i]--;
        G[i][u]--;
       // printf("%d %d\n",u,i);
        dfs2(i);
        printf("%d %d\n",i,u);
    }

}
int main()
{
    int t;
    cin>>t;
    int cas=0;
    while(t--)
    {
        cas++;
        memset(G,0,sizeof(G));
        memset(deg,0,sizeof(deg));
        memset(vis,0,sizeof(vis));
        cin>>n;
        for(int i=0;i<n;i++)
        {
            int a,b;
            cin>>a>>b;
            G[a][b]++;
            G[b][a]++;
            deg[a]++;
            deg[b]++;
        }
        int flag=1;
        for(int i=0;i<N;i++)
        {
            if(deg[i]%2)
            {
                flag=0;break;
            }

        }
     /*   if(flag)
        {
            for(int i=0;i<N;i++)
            if(deg[i]) {dfs(i);break;}

            for(int i=0;i<N;i++)
                if(deg[i]&&!vis[i]) {flag=0;break;}
        }*/
        printf("Case #%d\n",cas);
        if(flag)
        {
            for(int i=0;i<N;i++)
            {
                if(deg[i]) {dfs2(i);break;}
            }
        }
        else
            printf("some beads may be lost\n");
        if(t)
        cout<<endl;
    }
    return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值