欧拉回路的判定和求解

欧拉回路的判定

1无向图

 无向图:连通(不考虑度为 0 的点),每个顶点度数都为偶数。

hdu 1878

ac代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <string>
#include <cmath>
#include <cstdlib>

using namespace std;

const int MAXN = 3 * 100000 + 7;
const int INF = 0x7f7f7f7f;

/***************************
无向欧拉图的判断
***************************/

int d[1005],father[1005];

void init(int n)
{
    memset(d, 0,sizeof d);
    for(int i = 1; i <= n; i++) father[i] = i;
}

int getfa(int x)
{
    while(x != father[x])   x = father[x];
    return x;
}

int main()
{
    std::ios::sync_with_stdio(false);
    int n,m;
    while(cin>>n>>m){
        init(n);
        int sum = n;
        while(m--){
            int u,v;
            cin>>u>>v;
            d[u]++ , d[v]++;
            int x = getfa(u), y = getfa(v);
            if(x != y)  father[x] = y , sum--;
        }
        //如果图不联通
        if(sum  > 1){ 
            cout<<0<<endl;
            continue;
        }
        bool flag  = true;
        for(int i = 1; i <= n; i++){
            if(d[i] % 2){
                flag = false;
                cout<<0<<endl;
                break;
            }
        }
        if(flag)    cout<<1<<endl;
    }
    return 0;
}

2 有向图

欧拉路径存在的充要条件:
1.有向图存在欧拉回路的充要条件 所有顶点的 入度 和 出度 的和是 偶数,且该图是连通图(并查集)。
2.有向图含有欧拉通路的充要条件
起始点s 的入度=出度-1,结束点t的出度=入度-1 或两个点的入度=出度,且该图是连通图(并查集)。

题意:

  给你多个单词,问你能不能将所有单词组成这样一个序列:序列的前一个单词的尾字母与后一个单词的头字母相同.

把每个单词的首尾字符当作点,这个字符就是这两个点连出的一条边,也就是求有向图的欧拉路径

poj 1386

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <string>
#include <cmath>
#include <cstdlib>

using namespace std;

const int MAXN = 3 * 100000 + 7;
const int INF = 0x7f7f7f7f;

/***************************
有向欧拉图的判断
***************************/
int in[30],out[30],father[30];
bool exist[30];

void init()
{
    memset(out, 0 ,sizeof out);
    memset(in, 0,sizeof in);
    memset(exist , false , sizeof exist);
    for(int i = 0; i < 30; i++) father[i] = i;
}

int getfa(int x)
{
    while(x != father[x])   x = father[x];
    return x;
}

void marge(int x, int y)
{
    x = getfa(x) , y = getfa(y);
    if( x != y) father[x] = y;
}

int main()
{
    //std::ios::sync_with_stdio(false);
   int t;
   char str[1005];
   scanf("%d",&t);
   while(t--){
       int n;
       scanf("%d",&n);
       init();
       for(int i = 0; i < n; i++){
           scanf("%s",str);
           int len = strlen(str);
           int u = str[0] - 'a';
           int v = str[len - 1] - 'a';
           out[u]++ , in[v]++;
           exist[u] = exist[v] = true;
           marge(u,v);
       }
       int flag = 0;
       for(int i = 0; i < 26; i++){
           if(exist[i] && father[i] == i)    flag++;
       }
       if(flag >= 2){
            cout<<"The door cannot be opened."<<endl;
            continue;
       }
       int inn = 0, outn = 0,mark = 0;
       for(int i = 0; i < 26; i++){
           if(in[i] != out[i] && exist[i]){
               if(1 == in[i] - out[i])  inn++;//入度比出度大1
               else if(1 == out[i] - in[i]) outn++;
               else{
                   mark = 1;
                   break;
               }
           }
       }
       if(mark){
           cout<<"The door cannot be opened."<<endl;
           continue;
       }
       else{
           if(!(inn + outn) || (inn== 1 && outn == 1))    cout<<"Ordering is possible."<<endl;
           else     cout<<"The door cannot be opened."<<endl;
       }
   }
   return 0;
}

欧拉回路的求解

确实对于求解方式没有弄明白,先记录一下

  先给出模板

int stack[maxn];///maxn是边的最大数量
bool vis[maxn];
int bj;
void dfs(int now)
{
    for(int i=head[now];i!=-1;i=tu[i].next)
    if(!vis[i])
    {
        vis[i]=1;
        vis[i^1]=1;///这里是求欧拉回路,这一题用不着写这句,因为可以走双向,无向图
	      //在跑无向图的时候要加上这一句
        dfs(tu[i].to);
        stcak[bj++]=i;///等于i是记录边,等于tu[i].to是记录点
    }
}

这里的异或操作其实算是一种规律在存储无向图的时候由于我们存储的路的编号和这条路反方向的编号是连续的,比如 0,1、2 , 3这样我们对其中一个数求异或,得到的就是另一个数字,所以我们 采取这种方法把无向图的边给标记上。

poj2230

这个因为每条路可以正反方向走两次,所以直接当作存在两点之间的路径有两条有向边,然后当作有向图进行处理就可以了

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<iomanip>

using namespace std;

typedef long long ll;

const int N=10005;
const int maxn=100010;

int head[N];
int tot , ip;

struct edgenode
{
    int to;
    int next;
} tu[N * N];

void init()
{
    memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
    ip++, tu[ip].to = v, tu[ip].next = head[u], head[u] = ip;
}
 
int ans[maxn];
bool vis[maxn];

void dfs(int now)
{
    for(int i = head[now]; i != -1; i = tu[i].next)
        if(!vis[i])
        {
            vis[i] = 1;
            //vis[i^1]=1;
            dfs(tu[i].to);
            ans[tot++] = tu[i].to;
        }
}
 
int main()
{
    int m,n;
    scanf("%d%d",&n,&m);
    init();
    while(m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    memset(vis,0,sizeof(vis));
    memset(ans,0,sizeof(ans));
    tot = 0;
    dfs(1);
    for(int i = 0; i < tot; i++)
        cout<<ans[i]<<endl;
    cout<<1<<endl;
    return 0;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值