博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SGU 176 Flow construction
阅读量:6220 次
发布时间:2019-06-21

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

SGU_176

    一开始学习有上下界的网络流时都是看的这篇博客上的内容:,当看到有源汇最小流问题时怎么都觉得做两遍网络流的算法无论是时间复杂度还是编码复杂度都应该比用二分写更优,但是按那个解法写SGU 176 Flow construction却怎么也过不了,后来翻到了另一篇博客:,又发现了另一种做两遍网络流的算法,按这个的思想改了一下之前的代码就AC了,搞得我也莫名其妙的……不知道是不是对上面那边博客里的思想还没有理解到位……

View Code // 用第二篇博客的思想写成的代码
#include
#include
#include
#define MAXD 110#define MAXM 60010#define INF 0x3f3f3f3fint N, M, first[MAXD], e, next[MAXM], v[MAXM], flow[MAXM];int S, T, q[MAXD], d[MAXD], work[MAXD];struct Edge{ int x, y, low, high; }edge[MAXM];void add(int x, int y, int z){ v[e] = y, flow[e] = z; next[e] = first[x], first[x] = e ++;}void init(){ int i; S = 0, T = N + 1; memset(first, -1, sizeof(first[0]) * (N + 2)); e = 0; for(i = 0; i < M; i ++) { scanf("%d%d%d%d", &edge[i].x, &edge[i].y, &edge[i].high, &edge[i].low); if(edge[i].low) edge[i].low = edge[i].high; add(edge[i].x, edge[i].y, edge[i].high - edge[i].low), add(edge[i].y, edge[i].x, 0); }}void build(){ int i; for(i = 0; i < M; i ++) add(S, edge[i].y, edge[i].low), add(edge[i].y, S, 0), add(edge[i].x, T, edge[i].low), add(T, edge[i].x, 0);}int bfs(int S, int T){ int i, j, rear = 0; memset(d, -1, sizeof(d[0]) * (N + 2)); d[S] = 0, q[rear ++] = S; for(i = 0; i < rear; i ++) for(j = first[q[i]]; j != -1; j = next[j]) if(flow[j] && d[v[j]] == -1) { d[v[j]] = d[q[i]] + 1, q[rear ++] = v[j]; if(v[j] == T) return 1; } return 0;}int dfs(int cur, int a, int T){ if(cur == T) return a; for(int &i = work[cur]; i != -1; i = next[i]) if(flow[i] && d[v[i]] == d[cur] + 1) if(int t = dfs(v[i], std::min(a, flow[i]), T)) { flow[i] -= t, flow[i ^ 1] += t; return t; } return 0;}int dinic(int S, int T){ int ans = 0, t; while(bfs(S, T)) { memcpy(work, first, sizeof(first[0]) * (N + 2)); while(t = dfs(S, INF, T)) ans += t; } return ans;}void print(){ int i, j, k, ans = 0; for(i = first[1]; i != -1; i = next[i]) if(v[i] == N) ans = flow[i]; printf("%d\n", ans); printf("%d", flow[1] + edge[0].low); for(i = 1; i < M; i ++) printf(" %d", flow[i << 1 | 1] + edge[i].low); printf("\n");}int check(){ int i; for(i = first[S]; i != -1; i = next[i]) if(flow[i]) return 0; return 1; }void solve(){ build(); dinic(S, T); add(N, 1, INF), add(1, N, 0); dinic(S, T); if(!check()) printf("Impossible\n"); else print();}int main(){ while(scanf("%d%d", &N, &M) == 2) { init(); solve(); } return 0; }

 

    后记:后来突然想到第二篇博客上有说一种情况,就是有流流入点1的情况,于是这样在算需要流入点1的流量的时候应该是用原图中1这个点出去的流量减去从其他点流入点1的流量,改了之后果然AC了,果然还是自己有一些细节没有理解到位。

View Code // 用第一篇博客的思想写成的代码
#include
#include
#include
#define MAXD 110#define MAXM 60010#define INF 0x3f3f3f3fint N, M, first[MAXD], e, next[MAXM], v[MAXM], flow[MAXM];int S, T, q[MAXD], d[MAXD], work[MAXD];struct Edge{ int x, y, low, high; }edge[MAXM];void add(int x, int y, int z){ v[e] = y, flow[e] = z; next[e] = first[x], first[x] = e ++;}void init(){ int i; S = 0, T = N + 1; memset(first, -1, sizeof(first[0]) * (N + 2)); e = 0; for(i = 0; i < M; i ++) { scanf("%d%d%d%d", &edge[i].x, &edge[i].y, &edge[i].high, &edge[i].low); if(edge[i].low) edge[i].low = edge[i].high; add(edge[i].x, edge[i].y, edge[i].high - edge[i].low), add(edge[i].y, edge[i].x, 0); }}int build(){ int i, sum = 0; for(i = 0; i < M; i ++) { add(S, edge[i].y, edge[i].low), add(edge[i].y, S, 0), add(edge[i].x, T, edge[i].low), add(T, edge[i].x, 0); sum += edge[i].low; } add(N, 1, INF), add(1, N, 0); return sum;}int bfs(int S, int T){ int i, j, rear = 0; memset(d, -1, sizeof(d[0]) * (N + 2)); d[S] = 0, q[rear ++] = S; for(i = 0; i < rear; i ++) for(j = first[q[i]]; j != -1; j = next[j]) if(flow[j] && d[v[j]] == -1) { d[v[j]] = d[q[i]] + 1, q[rear ++] = v[j]; if(v[j] == T) return 1; } return 0;}int dfs(int cur, int a, int T){ if(cur == T) return a; for(int &i = work[cur]; i != -1; i = next[i]) if(flow[i] && d[v[i]] == d[cur] + 1) if(int t = dfs(v[i], std::min(a, flow[i]), T)) { flow[i] -= t, flow[i ^ 1] += t; return t; } return 0;}int dinic(int S, int T){ int ans = 0, t; while(bfs(S, T)) { memcpy(work, first, sizeof(first[0]) * (N + 2)); while(t = dfs(S, INF, T)) ans += t; } return ans;}void print(){ int i, j, k, ans = 0; for(i = 0; i < M; i ++) { if(edge[i].x == 1) ans += flow[i << 1 | 1] + edge[i].low; if(edge[i].y == 1) ans -= flow[i << 1 | 1] + edge[i].low; } printf("%d\n", ans); printf("%d", flow[1] + edge[0].low); for(i = 1; i < M; i ++) printf(" %d", flow[i << 1 | 1] + edge[i].low); printf("\n");}void solve(){ int ans = build(); if(ans != dinic(S, T)) printf("Impossible\n"); else { dinic(N, 1); print(); }}int main(){ while(scanf("%d%d", &N, &M) == 2) { init(); solve(); } return 0; }

 

 

 

转载地址:http://oleja.baihongyu.com/

你可能感兴趣的文章
文本溢出省略号显示时,水平位置发生偏移
查看>>
和真正的程序员在一起是怎样的体验
查看>>
Python之sys模块
查看>>
接口自动化框架好文
查看>>
K3Cloud调用存储过程
查看>>
第212天:15种CSS居中的方式,最全了
查看>>
SQL Server 2008 FILESTREAM特性管理文件
查看>>
javascript基础-闭包
查看>>
试了一下一致性哈希(consistent hashing)
查看>>
2014-1-2 笔记
查看>>
C++之shared_ptr总结
查看>>
iis6 元数据库与iis6 配置的兼容 出错问题
查看>>
typeof 操作符
查看>>
整合资源_java的基础关键字
查看>>
洛谷 2678 跳石头——二分答案
查看>>
洛谷1462通往奥格瑞玛的道路
查看>>
RabbitMQ操作方法
查看>>
如何升级到SQL Server 2005
查看>>
CSS样式详解
查看>>
常用正则匹配
查看>>