hdu 3667 Transportation【费用流 + 拆边】
2015-09-05 03:12
471 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3667
解法:大白书366页,拆边法
SPFA代码(AC):
zkw费用流代码(超时)(对二分图类型效率高):
解法:大白书366页,拆边法
SPFA代码(AC):
[code]#include <iostream> #include <algorithm> #include <set> #include <map> #include <string.h> #include <queue> #include <sstream> #include <stdio.h> #include <math.h> #include <stdlib.h> #include <string> using namespace std; const int MAXN = 10000; const int MAXM = 200000; const int INF = 0x3f3f3f3f; struct Edge { int to, next, cap, flow, cost; }edge[MAXM]; int head[MAXN], tol; int pre[MAXN], dis[MAXN]; bool vis[MAXN]; int N; void init(int n) { N = n; tol = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v, int cap, int cost) { edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } bool spfa(int s, int t) { queue<int>q; for (int i = 0;i < N;i++) { dis[i] = INF; vis[i] = false; pre[i] = -1; } dis[s] = 0; vis[s] = true; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for (int i = head[u];i != -1;i = edge[i].next) { int v = edge[i].to; if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if (!vis[v]) { vis[v] = true; q.push(v); } } } } if (pre[t] == -1)return false; else return true; } int minCostMaxflow(int s, int t, int &cost) { int flow = 0; cost = 0; while (spfa(s, t)) { int Min = INF; for (int i = pre[t];i != -1;i = pre[edge[i ^ 1].to]) { if (Min > edge[i].cap - edge[i].flow) Min = edge[i].cap - edge[i].flow; } for (int i = pre[t];i != -1;i = pre[edge[i ^ 1].to]) { edge[i].flow += Min; edge[i ^ 1].flow -= Min; cost += edge[i].cost*Min; } flow += Min; } return flow; } int n, m, k, ans; int cnt[10] = { 0,1,3,5,7,9 }; int main() { while (~scanf("%d%d%d", &n, &m, &k)) { init(n + 2); addedge(0, 1, k, 0); addedge(n, n + 1, k, 0); int u, v, a, c; for (int i = 1;i <= m;i++) { scanf("%d%d%d%d", &u, &v, &a, &c); for (int j = 1;j <= c;j++) addedge(u, v, 1, a*cnt[j]); } int tmp = minCostMaxflow(0, n + 1, ans); if (ans < k) puts("-1"); else printf("%d\n", ans); } return 0; }
zkw费用流代码(超时)(对二分图类型效率高):
[code]#include <iostream> #include <algorithm> #include <set> #include <map> #include <string.h> #include <queue> #include <sstream> #include <stdio.h> #include <math.h> #include <stdlib.h> #include <string> using namespace std; const int MAXN = 1000; const int MAXM = 200000; const int INF = 0x3f3f3f3f; struct Edge { int to, next, cap, flow, cost; Edge(int _to = 0, int _next = 0, int _cap = 0, int _flow = 0, int _cost = 0) : to(_to), next(_next), cap(_cap), flow(_flow), cost(_cost) {} }edge[MAXM]; struct ZKW_MinCostMaxFlow { int head[MAXN], tot; int cur[MAXN]; int dis[MAXN]; bool vis[MAXN]; int ss, tt, N;//源点、汇点和点的总个数(编号是0~N-1),不需要额外赋值,调用会直接赋值 int min_cost, max_flow; void init() { tot = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v, int cap, int cost) { edge[tot] = Edge(v, head[u], cap, 0, cost); head[u] = tot++; edge[tot] = Edge(u, head[v], 0, 0, -cost); head[v] = tot++; } int aug(int u, int flow) { if (u == tt)return flow; vis[u] = true; for (int i = cur[u];i != -1;i = edge[i].next) { int v = edge[i].to; if (edge[i].cap > edge[i].flow && !vis[v] && dis[u] == dis[v] + edge[i].cost) { int tmp = aug(v, min(flow, edge[i].cap - edge[i].flow)); edge[i].flow += tmp; edge[i ^ 1].flow -= tmp; cur[u] = i; if (tmp)return tmp; } } return 0; } bool modify_label() { int d = INF; for (int u = 0;u < N;u++) if (vis[u]) for (int i = head[u];i != -1;i = edge[i].next) { int v = edge[i].to; if (edge[i].cap>edge[i].flow && !vis[v]) d = min(d, dis[v] + edge[i].cost - dis[u]); } if (d == INF)return false; for (int i = 0;i < N;i++) if (vis[i]) { vis[i] = false; dis[i] += d; } return true; } /* * 直接调用获取最小费用和最大流 * 输入: start-源点,end-汇点,n-点的总个数(编号从0开始) * 返回值: pair<int,int> 第一个是最小费用,第二个是最大流 */ pair<int, int> mincostmaxflow(int start, int end, int n) { ss = start, tt = end, N = n; min_cost = max_flow = 0; for (int i = 0;i < n;i++)dis[i] = 0; while (1) { for (int i = 0;i < n;i++)cur[i] = head[i]; while (1) { for (int i = 0;i < n;i++)vis[i] = false; int tmp = aug(ss, INF); if (tmp == 0)break; max_flow += tmp; min_cost += tmp*dis[ss]; } if (!modify_label())break; } return make_pair(min_cost, max_flow); } }solve; int n, m, k; int cnt[10] = { 0,1,3,5,7,9 }; int main() { while (~scanf("%d%d%d", &n, &m, &k)) { solve.init(); solve.addedge(0, 1, k, 0); solve.addedge(n, n + 1, k, 0); int u, v, a, c; for (int i = 1;i <= m;i++) { scanf("%d%d%d%d", &u, &v, &a, &c); for (int j = 1;j <= c;j++) solve.addedge(u, v, 1, a*cnt[j]); } pair<int, int> tmp = solve.mincostmaxflow(0, n + 1, n + 2); int ans = tmp.second; if (ans < k) puts("-1"); else printf("%d\n", tmp.first); } return 0; }
相关文章推荐
- 《你必须知道的.NET》读书实践:一个基于OO的万能加载器的实现
- 双飞翼布局(圣杯布局)介绍-始于淘宝UED
- Java堆.栈和常量池 笔记
- 圣杯布局与双飞翼布局的实现思路
- 圣杯布局与双飞翼布局的实现思路
- CSS布局奇淫巧计之-强大的负边距
- UVA 11235-Frequent values-RMQ(st表)+游程编码
- 一个简单的线程池
- Tomcat源码阅读系列(七)Session管理机制
- iOS开发脚踏实地学习day02-图片查看器和TOM猫
- python 函数的调用 和执行 小知识
- Design Pattern Explained 读书笔记五——Bridge
- Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)
- Android Studio 中快速提取方法
- Linux文件系统的创建及挂载
- 经典算法:计算两个日期之间的天数
- Android Studio之Gradle多渠道打包
- 如何使用Shiro实现不同用户登录成功后跳转到不同主页?
- 求一元多项式
- LeetCode Invert Binary Tree