hdu3251 最小割
来源:互联网 发布:打字淘宝兼职是真的吗 编辑:程序博客网 时间:2024/05/16 08:41
http://acm.hdu.edu.cn/showproblem.php?pid=3251
题意:
给定一张图,可以选择一些点,每个点有对应的点权,每条边有边权,选择一部分点后,必须摧毁一部分边,保证 1 不能到达这些点,获得的收益就是选择的点权和减去摧毁的边权和。并求出摧毁哪些边。
做法:
将带权的点连接一条边到t点,容量为该点的点权。最后将s连到1,容量为inf。求最小割,利用总的点权和减去最小割就是获得的收益。因为如果这个点不选择的话,最小割肯定包含该点到t点的边。如果要选择的话,肯定不包含,必须包含之前的点。
求摧毁的边,就可以跑完最大流以后,用dfs求一遍,将图划分成两个集合,如果一条边的起点与s在同一个集合,终点与t在同一个集合那么这条就是割边,(并且要排除掉与t相连的那些割边)。
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <set>#include <stack>#include <vector>using namespace std;const int M_node = 4000,M_edge = 210009,INF = 0x3f3f3f3f;struct edge{ int to,cap,next; int index;}edge[M_edge];int head[M_node],iter[M_node];int level[M_node];bool vis[M_node];int num;int n,m,f,s,t;int sum;void init(){ memset(head,-1,sizeof(head)); memset(vis,false,sizeof(vis)); num = 0; sum = 0;}void add_edge(int u,int v,int cap,int index){ edge[num].to = v; edge[num].cap = cap ; edge[num].next = head[u] ; edge[num].index = index ; head[u] = num++; edge[num].to = u; edge[num].cap = 0 ; edge[num].next = head[v] ; edge[num].index = -1 ; head[v] = num++;}bool bfs(int s,int t){ memset(level,-1,sizeof(level)); level[s] = 0; queue<int> q; q.push(s); while(!q.empty()) { int v = q.front(); q.pop(); for(int i = head[v];i != -1;i = edge[i].next) { int u = edge[i].to; if(level[u] < 0 && edge[i].cap) { level[u] = level[v] + 1; q.push(u); } } } return level[t] != -1;}int dfs(int v,int t,int f){ if(v == t) return f; for(int &i = iter[v];i != -1;i = edge[i].next) { int u = edge[i].to; if(level[u] > level[v] && edge[i].cap > 0) { int d = dfs(u,t,min(f,edge[i].cap)); if(d > 0) { edge[i].cap -= d; edge[i^1].cap += d; return d; } } } level[v] = -1; return 0;}int max_flow(int s,int t){ int flow = 0; while(bfs(s,t)) { for(int i = 0;i <= t+10;i++) iter[i] = head[i]; int f = 0; while((f = dfs(s,t,INF)) > 0) flow += f; } return flow;}void dfs(int u,int fa){ for(int i = head[u];i != -1;i = edge[i].next) { int v = edge[i].to; if(!vis[v] && edge[i].cap > 0) { vis[v] = true; dfs(v,u); } }}int main(){ int T; scanf("%d",&T); int kas = 1; while(T--) { scanf("%d%d%d",&n,&m,&f); init(); s = 0; t = n+1; add_edge(s,1,INF,-1); for(int i = 0;i < m;i++) { int u,v,cap; scanf("%d%d%d",&u,&v,&cap); add_edge(u,v,cap,i+1); } for(int i = 0;i < f;i++) { int u,cost; scanf("%d%d",&u,&cost); add_edge(u,t,cost,-1); sum += cost; } int ans = max_flow(s,t); ans = sum - ans; printf("Case %d: %d\n",kas++,ans); vis[1] = true; dfs(1,-1); queue<int> q; for(int i = 0;i < num;i += 2) // += 2 保证是正向边 { if(vis[edge[i^1].to] && !vis[edge[i].to] && edge[i].index != -1) q.push(edge[i].index); } printf("%d",q.size()); while(!q.empty()) { printf(" %d",q.front()); q.pop(); } printf("\n"); /*set<int> s; for(int i = 1;i <= n;i++) { for(int j = head[i]; j != -1 ;j = edge[j].next) { int v = edge[j].to; if(vis[i] && !vis[v] && edge[j].index != -1) s.insert(edge[j].index); //必须保证是正向边 } } printf("%d",s.size()); set<int>::iterator it; for(it = s.begin();it != s.end();it++) { printf(" %d",*it); } printf("\n");*/ } return 0;}
0 0
- hdu3251 最小割
- hdu3251 最小割
- 最小割
- 最小割
- 最小割
- 最小割
- 【最小割】bzoj:1797最小割
- 2229: [Zjoi2011]最小割 最小割
- 【bzoj2229】【ZJOI2229】【最小割】【最小割】
- Bzoj2229:[Zjoi2011]最小割:分治最小割
- bzoj 1797 最小割【最小割】【tarjan】
- ZJOI2011最小割 最小割树
- BZOJ2229: [Zjoi2011]最小割 分治最小割
- 求割边最小的最小割
- pku3084 最小割
- 最大流/最小割
- poj 3084(最小割。。。。。)
- 【最小割】ustc 1280
- 模态弹出的页面push或pop到其他页面
- 基于R语言的用户征信行为分类预测模型搭建总结
- NAT和代理服务器解析
- 最近遇到的一些问题以及解决方案
- python gzip模块
- hdu3251 最小割
- **PDO** php_mysql插入查询排序
- Android中的Service:默默的奉献者 (1)
- C语言 关键字!!面试常碰到!
- java实现2048
- python 使用socket搭建简单服务器
- Struts2+Hibernate5+Spring4自学历程(1)
- jquery实现擦除效果
- getopt