HDU 3987 Harry Potter and the Forbidden Forest
2013-10-31 21:22
363 查看
题意:给出一张有n个点的图,有的边又向,有的边无向,现在要你破坏一些路,使得从点0无法到达点n-1。破坏每条路都有一个代价。求在代价最小的前提下,最少需要破坏多少条道路。(就是说求在最小割的前提下,最小的割边数)
这题做了长姿势了。偏移量的方法没有想到。如果采用偏移量的方法的话,把每条边的边权w设为w'=w*MOD+1,然后求最小割,那么maxflow%MOD就是答案了。前提是MOD足够大。
另外一种方法,利用一个结论:最小割边一定满流,满流的未必是最小割边。假设所有满流的边都是最小割边,把它们的cap全部设为1,其余未满流的边的cap设为inf,然后求最小割,答案就是最小割值。虽然没搞懂怎么证明这个做法是对的,也觉得这个做法有点邪乎,但它就是对的。也就是说,最小割不唯一的情况下,未出现在一个最小割中却出现在另外一个最小割中的边一定也是满流的(真不知道到底对不对)。
代码:
View Code
这题做了长姿势了。偏移量的方法没有想到。如果采用偏移量的方法的话,把每条边的边权w设为w'=w*MOD+1,然后求最小割,那么maxflow%MOD就是答案了。前提是MOD足够大。
另外一种方法,利用一个结论:最小割边一定满流,满流的未必是最小割边。假设所有满流的边都是最小割边,把它们的cap全部设为1,其余未满流的边的cap设为inf,然后求最小割,答案就是最小割值。虽然没搞懂怎么证明这个做法是对的,也觉得这个做法有点邪乎,但它就是对的。也就是说,最小割不唯一的情况下,未出现在一个最小割中却出现在另外一个最小割中的边一定也是满流的(真不知道到底对不对)。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define INF 1<<30 #define maxn 1010 #define maxm 500000 using namespace std; int v[maxm],next[maxm],w[maxm]; int first[maxn],d[maxn],work[maxn],q[maxn]; int e,S,T; void init(){ e = 0; memset(first,-1,sizeof(first)); } void add_edge(int a,int b,int c){ v[e] = b;next[e] = first[a];w[e] = c;first[a] = e++; v[e] = a;next[e] = first[b];w[e] = 0;first[b] = e++; } int bfs(){ int rear = 0; memset(d,-1,sizeof(d)); d[S] = 0;q[rear++] = S; for(int i = 0;i < rear;i++){ for(int j = first[q[i]];j != -1;j = next[j]) if(w[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){ if(cur == T) return a; for(int &i = work[cur];i != -1;i = next[i]){ if(w[i] && d[v[i]] == d[cur] + 1) if(int t = dfs(v[i],min(a,w[i]))){ w[i] -= t;w[i^1] += t; return t; } } return 0; } int dinic(){ int ans = 0; while(bfs()){ memcpy(work,first,sizeof(first)); while(int t = dfs(S,INF)) ans += t; } return ans; } int main() { int n,m,nkase; scanf("%d",&nkase); for(int kase = 1;kase <= nkase;kase++){ init(); scanf("%d%d",&n,&m); S = 0,T = n-1; for(int i = 0;i < m;i++){ int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); add_edge(a,b,c); if(d == 1) add_edge(b,a,c); } dinic(); for(int i = 0;i < e;i += 2){ if(w[i] == 0){ w[i] = 1; w[i^1] = 0; }else{ w[i] = INF; w[i^1] = 0; } } printf("Case %d: %d\n",kase,dinic()); } return 0; }
View Code
相关文章推荐
- ubuntu下搭建nagios
- zedboard--嵌入式网络摄像机(mjpg-streamer)的移植和搭建(二十二)
- 把mysql数据库生成数据字典,直接可用
- jquery中的$(this)和js的document.getElementById(this)的区别
- Swing之JTable内容过滤文本框
- select accept
- 一道关于STL list笔试题,删除指定下标的元素
- 如何识别高级的验证码
- [转]python 之字典{}(Hashmap)
- 给电脑装完系统之后,发现U盘少了几个G!
- (队列的应用5.3.3)POJ 3125 Printer Queue(优先队列的使用)
- 中山大学东校区配置 OH3C 路由,oh3c 提示can't load library 'libz.so'
- [翻译Joel On Software]选择一门语言/Choosing a language
- 添加Action View
- 关于undefined reference to `WSASocketA@24'问题的解决
- hdu 1007 Quoit Design(分治法求最近点对)
- 我的2013校招总结
- 主成分分析
- poj2142 The Balance 扩展欧几里德的应用 稍微还是有点难度的
- 杭电1003 MAX SUN