博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ 1637 Sightseeing tour ★混合图欧拉回路
阅读量:5257 次
发布时间:2019-06-14

本文共 4793 字,大约阅读时间需要 15 分钟。

题目大意】混合图欧拉回路(1 <= N <= 200, 1 <= M <= 1000) 【
建模方法】 把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。 好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出=入。如果每个点都是出=入,那么很明显,该图就存在欧拉回路。 现在的问题就变成了:我该改变哪些边,可以让每个点出=入?构造网络流模型。首先,有向边是不能改变方向的,要之无用,删。一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入>出的点u,连接边(u, t)、容量为x,对于出>入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。之后,察看是否有
满流(最大流=从源点出去的流量)的分配。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个?察看流值分配,将所有流量非 0(上限是1,流值不是0就是1)的边反向,就能得到每点入度=出度的欧拉图。 由于是满流,所以每个入>出的点,都有x条边进来,将这些进来的边反向,OK,入=出了。对于出>入的点亦然。那么,没和s、t连接的点怎么办?和s连接的条件是出>入,和t连接的条件是入>出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入=出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。 所以,就这样,混合图欧拉回路问题,解了。
#include #include #include #include #include #include #include #include #include #include #include #define MID(x,y) ((x+y)/2)#define mem(a,b) memset(a,b,sizeof(a))using namespace std;const int MAXV = 305;const int MAXE = 10005;struct node{    int u, v, flow;    int opp;    int next;};struct Dinic{    node arc[MAXE];    int vn, en, head[MAXV];     //vn点个数(包括源点汇点),en边个数    int cur[MAXV];              //当前弧    int q[MAXV];                //bfs建层次图时的队列    int path[MAXE], top;        //存dfs当前最短路径的栈    int dep[MAXV];              //各节点层次    void init(int n){        vn = n;        en = 0;        mem(head, -1);    }    void insert_flow(int u, int v, int flow){        arc[en].u = u;        arc[en].v = v;        arc[en].flow = flow;        arc[en].opp = en + 1;        arc[en].next = head[u];        head[u] = en ++;        arc[en].u = v;        arc[en].v = u;        arc[en].flow = 0;       //反向弧        arc[en].opp = en - 1;        arc[en].next = head[v];        head[v] = en ++;    }    bool bfs(int s, int t){        mem(dep, -1);        int lq = 0, rq = 1;        dep[s] = 0;        q[lq] = s;        while(lq < rq){            int u = q[lq ++];            if (u == t){                return true;            }            for (int i = head[u]; i != -1; i = arc[i].next){                int v = arc[i].v;                if (dep[v] == -1 && arc[i].flow > 0){                    dep[v] = dep[u] + 1;                    q[rq ++] = v;                }            }        }        return false;    }    int solve(int s, int t){        int maxflow = 0;        while(bfs(s, t)){            int i, j;            for (i = 1; i <= vn; i ++)  cur[i] = head[i];            for (i = s, top = 0;;){                if (i == t){                    int mink;                    int minflow = 0x3fffffff;                    for (int k = 0; k < top; k ++)                        if (minflow > arc[path[k]].flow){                            minflow = arc[path[k]].flow;                            mink = k;                        }                    for (int k = 0; k < top; k ++)                        arc[path[k]].flow -= minflow, arc[arc[path[k]].opp].flow += minflow;                    maxflow += minflow;                    top = mink;		//arc[mink]这条边流量变为0, 则直接回溯到该边的起点即可(这条边将不再包含在增广路内).                    i = arc[path[top]].u;                }                for (j = cur[i]; j != -1; cur[i] = j = arc[j].next){                    int v = arc[j].v;                    if (arc[j].flow && dep[v] == dep[i] + 1)                        break;                }                if (j != -1){                    path[top ++] = j;                    i = arc[j].v;                }                else{                    if (top == 0)   break;                    dep[i] = -1;                    i = arc[path[-- top]].u;                }            }        }        return maxflow;    }}dinic;int indeg[MAXV], outdeg[MAXV];int main(){    int t;    scanf("%d", &t);    while (t --){        mem(indeg, 0);        mem(outdeg, 0);        int n, m;        scanf("%d %d", &n, &m);        dinic.init(n+2);        for (int i = 0; i < m; i ++){            int u, v, w;            scanf("%d %d %d", &u, &v, &w);            indeg[v] ++, outdeg[u] ++;            if (w == 0)                dinic.insert_flow(u, v, 1);        }        bool ok = 1;        int sum = 0;        for (int i = 1; i <= n; i ++){            int x = abs(indeg[i] - outdeg[i]);            if (x == 0)                continue;            if (x % 2 == 1){                ok = 0;                break;            }            if (indeg[i] > outdeg[i]){                dinic.insert_flow(i, n+2, x/2);                sum += x/2;            }            else{                dinic.insert_flow(n+1, i, x/2);            }        }        if (!ok){            puts("impossible");            continue;        }        if (dinic.solve(n+1, n+2) == sum){            puts("possible");        }        else{            puts("impossible");        }    }	return 0;}

转载于:https://www.cnblogs.com/AbandonZHANG/p/4114254.html

你可能感兴趣的文章
CentOS
查看>>
Linux pipe函数
查看>>
java equals 小记
查看>>
爬虫-通用代码框架
查看>>
2019春 软件工程实践 助教总结
查看>>
YUV 格式的视频呈现
查看>>
现代程序设计 作业1
查看>>
在android开发中添加外挂字体
查看>>
Zerver是一个C#开发的Nginx+PHP+Mysql+memcached+redis绿色集成开发环境
查看>>
多线程实现资源共享的问题学习与总结
查看>>
java实现哈弗曼树
查看>>
转:Web 测试的创作与调试技术
查看>>
python学习笔记3-列表
查看>>
程序的静态链接,动态链接和装载 (补充)
查看>>
关于本博客说明
查看>>
线程androidAndroid ConditionVariable的用法
查看>>
转载:ASP.NET Core 在 JSON 文件中配置依赖注入
查看>>
socket初识
查看>>
磁盘测试工具
查看>>
代码变量、函数命名神奇网站
查看>>