欧拉路径&&欧拉回路

来源:互联网 发布:ps4实况2018网络对战 编辑:程序博客网 时间:2024/04/28 12:19

欧拉回路

无向图:图连通且每个点的度均为偶数

有向图:图连通且每个点入度等于出度

欧拉路径

无向图:图连通且只有两个奇点

有向图:图连通且一个点出度-入度为1,一个点入度-出度为1,其他点均入度等于出度

混合图的欧拉回路

1、随意定向

在混合图中,对于双向边的处理除了拆边之外,还有任意定向。先对全图的双向边进行任意定向,计算出度和入度,如果一个点的出度加入度是奇数的话,那么这个图中没有欧拉回路。虽然随意定向是没有依据的,但是可以使用这样的随机化处理方法,再使用恰当的调整方法构造出解。

2、自调整方法

将其中的一些边的方向调整回来,使所有的点的出度等于入度。但是有一条边的方向改变后,可能会改变一个点的出度的同时改变另一个点的入度,相当于一条边制约着两个点。同时有些点的出度大于入度,迫切希望它的某些点出边转向;而有些点的入度大于出度,迫切希望它的某些入边转向。这两条边虽然需求不同,但是他们之间往往一条边转向就能同时满足二者。

具体步骤:

1、另 x = |入度-出度| / 2,对于不同的点有不同的x值,这个x值代表它们在邻接表中相应调整x条就能让出度等于入度

2、把图中的点转换为一个二分图,每个点的x值就是它们的点权。

3、源点S向所有出度>入度的点连边,汇点T向所有入度大于出度的点连边,将各自的点权转换为边权。

4、最后将原图中所有暂时定向的无向边加上一个1的容量,方向不变,而有向边不能改变方向,不需连边

可以发现,从源点S出发的一个单位流将会把一个“无向边”的容量变为0,使得两端的点权各自减1,其实这就是在模拟一次对无向边方向的调整。当把图建好后,依靠最大流性质可以最大可能地无冲突调整边的方向,并最终使得每个点的点容量都达到满流。对那些图中出度等于入度的点做适当分析,它们作为一个“中间点”,由于流平衡性质,不会留下任何流量值,对于那些真正需要调整的点不会带来任何影响。最后检查从源点出发的每条边是否都满流,如果有一条边没有满流,说明有一个点没有调整到入度等于出度,于是整个图不存在欧拉回路。

例题

从一个点出发逛遍所有的路回到出发点,路分为单行路和双行路,这就是一个混合图求欧拉回路的问题。

#include <math.h>#include <vector>#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>using namespace std;const int MAXV = 1010;const int MAXE = 50010;const int INF = 0x3f3f3f3f;int n,m;int S,T;int totflow;//满流大小int dis[MAXV],vis[MAXV],Q[MAXV],h,t;int out[MAXV],in[MAXV],head[MAXV],cnt;struct edge{    int u,v,c,next;}node[MAXE];void Init(){    cnt = 0, totflow = 0;    memset(in, 0, sizeof(in));    memset(out, 0, sizeof(out));    memset(head, -1, sizeof(head));}void addedge(int u, int v, int c){//构建邻接表    node[cnt].v = v;    node[cnt].c = c;    node[cnt].next = head[u];    head[u] = cnt++;}int buildflow(){//创建最大流模型    int flag = true;    S = 0, T = n+1;    for(int i=1; i<=n; i++){        if((out[i] + in[i]) & 1) return 0;        else if(out[i] > in[i]){            int c = (out[i] - in[i]) >> 1;            addedge(S, i, c);            addedge(i, S, 0);            totflow += c;        }         else{            int c = in[i] - out[i];            addedge(i, T, c/2);            addedge(T, i, 0);        }    }    return 1;}int BFS(){//构建层次图    memset(dis, -1, sizeof(dis));    Q[1] = S, h = 0, t = 1;    dis[S] = 0;    while(h < t){        int u = Q[++h];        for(int i=head[u]; i!=-1; i=node[i].next){            int v = node[i].v, c = node[i].c;            if(dis[v] == -1 && c){                dis[v] = dis[u] + 1;                Q[++t] = v;                if(v == T) return true;            }        }    }    return false;}int DFS(int id, int minflow){//Dinic算法过程    if(id == T) return minflow;    int a = 0;    for(int i=head[id]; i!=-1; i=node[i].next){        int v = node[i].v, c = node[i].c;        if(c > 0 && dis[v] == dis[id] + 1             && (a = DFS(v, min(minflow, c)))){            node[i].c -= a;            node[i^1].c += a;            return a;        }    }    return 0;}int Dinic(){    int tmp,ans = 0;    while(BFS()){        while(tmp = DFS(S, INF)) ans += tmp;    }    return ans;}int main(){    int t;    scanf("%d",&t);    while(t--){        Init();        scanf("%d%d",&n,&m);        while(m--){            int u,v,d;            scanf("%d%d%d",&u,&v,&d);            out[u]++, in[v]++;            if(u == v) continue;            if(d) continue;            addedge(u, v, 1);            addedge(v, u, 0);        }        int flag = buildflow(),  ans = Dinic();        if(!flag) puts("impossible");        else if(ans >= totflow) puts("possible");          else puts("impossible");       }    return 0;}



0 0
原创粉丝点击