2017 暑假艾教集训 day12 网络流(最大流 最小割)!
来源:互联网 发布:入住淘宝达人 编辑:程序博客网 时间:2024/06/16 06:49
模板
using namespace std;int n,m;const int maxn=1005;struct node{ int to,next,cap;}edge[maxn<<2];int head[maxn],cnt;void add(int u,int v,int w){ edge[cnt].to=v; edge[cnt].next=head[u]; edge[cnt].cap=w; head[u]=cnt++;}int deep[maxn];int bfs(int s,int t){ memset(deep,-1,sizeof(deep)); deep[s]=0; queue<int> que; que.push(s); while(!que.empty()) { int u=que.front(); que.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(deep[v]==-1 && edge[i].cap>0) { deep[v]=deep[u]+1; que.push(v); } } } return deep[t]!=-1;}int dfs(int u,int t,int maxflow){ if(u==t || maxflow==0) return maxflow; int flow=0; for(int i=head[u];i!=-1; i=edge[i].next) { int v=edge[i].to; if(deep[v]==deep[u]+1 && edge[i].cap>0) { int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) ); if(temp) { edge[i].cap -=temp; edge[i^1].cap+=temp; flow += temp; if(maxflow==flow) break; } } } if(!flow) deep[u]=-1; return flow;}int dinic(int s,int t){ int ans=0; while(bfs(s,t)) { ans+=dfs(s,t,0x3f3f3f3f); } return ans;}
POJ 1149
做法:建图是关键
建立超级起点汇点,每个顾客用一个点表示。
超级起点向每个猪圈第一个客人连猪圈的初始权值
每个猪圈的第I个客户向第I+1的客户连一条容量为inf 的边。
每个客户向超级汇点连一个容量为其最大购买容量的边!
POJ 1637
做法:存在欧拉回路的充要条件为每个点出入度相等,有向边无法改变方向对出入度影响是定值,重点在于无向边,初始时方向随意,若此时存在某点的出入度之差为奇数则不存在欧拉回路。设每个点出度-入度为x。 则该点的权值为x/2 。每改变一条相连的边出入度差值改变为2, 删除所有有向边,x/2>0与起点 连一条边,否则与汇点连一条边,如果最后满流这就说明了 存在欧拉回路
#include <cstring>#include <cstdio>#include <algorithm>#include <queue>using namespace std;int n,m;const int maxn=3005;struct node{ int to,next,cap;}edge[maxn<<2];int head[maxn],cnt;void add(int u,int v,int w){ edge[cnt].to=v; edge[cnt].next=head[u]; edge[cnt].cap=w; head[u]=cnt++;}int deep[maxn];int bfs(int s,int t){ memset(deep,-1,sizeof(deep)); deep[s]=0; queue<int> que; que.push(s); while(!que.empty()) { int u=que.front(); que.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(deep[v]==-1 && edge[i].cap>0) { deep[v]=deep[u]+1; que.push(v); } } } return deep[t]!=-1;}int dfs(int u,int t,int maxflow){ if(u==t || maxflow==0) return maxflow; int flow=0; for(int i=head[u];i!=-1; i=edge[i].next) { int v=edge[i].to; if(deep[v]==deep[u]+1 && edge[i].cap>0) { int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) ); if(temp) { edge[i].cap -=temp; edge[i^1].cap+=temp; flow += temp; if(maxflow==flow) break; } } } if(!flow) deep[u]=-1; return flow;}int dinic(int s,int t){ int ans=0; while(bfs(s,t)) { ans+=dfs(s,t,0x3f3f3f3f); } return ans;}int in[maxn],out[maxn];void init(){ memset(head,-1,sizeof(head)); cnt=0; memset(out,0,sizeof(out)); memset(in,0,sizeof(in)); scanf("%d%d",&n,&m); for(int i=1;i<=m;++i) { int a,b,c; scanf("%d%d%d",&a,&b,&c); in[b]++ ;out[a]++; if(c==0) { add(a,b,1); add(b,a,0); } }}int work(){ for(int i=1;i<=n;++i) { int temp=in[i]-out[i]; if( (temp%2+2)%2==1) return 0; } int sum=0; for(int i=1;i<=n;++i) { int temp=out[i]-in[i]; if(temp>0) { add(0,i,temp/2); add(i,0,0); } else if(temp<0) { temp= -temp; add(i,n+1,temp/2); add(n+1,i,0);sum+=(temp/2); } } if(sum==dinic(0,n+1)) return 1; return 0;}int main(){ int T; scanf("%d",&T); while(T--) { init(); if(work()) printf("possible\n"); else printf("impossible\n"); } return 0;}
POJ 2391
做法:二分时间 检验的时候将小于mid的边都加入,判断是否满流即可(要用floyd求出各个点之间的最短路)
#include <stdio.h>#include <cstring>#include <algorithm>#include <queue>#include <iostream>using namespace std;typedef long long ll;ll map[250][250];int a[25000],b[25000],n,m,sum;int s,t;struct node{ int to,next,cap;}edge[200*200*10];int head[250*10],cnt,deep[250*10];void add(int u,int v,int w){ edge[cnt].to=v; edge[cnt].next=head[u]; edge[cnt].cap=w; head[u]=cnt++;}int bfs(int s,int t){ memset(deep,-1,sizeof(deep)); deep[s]=0; queue<int> que; que.push(s); while(!que.empty()) { int u=que.front(); que.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(deep[v]==-1 && edge[i].cap>0) { deep[v]=deep[u]+1; que.push(v); } } } return deep[t]!=-1;}int dfs(int u,int t,int maxflow){ if(u==t || maxflow==0) return maxflow; int flow=0; for(int i=head[u];i!=-1; i=edge[i].next) { int v=edge[i].to; if(deep[v]==deep[u]+1 && edge[i].cap>0) { int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) ); if(temp) { edge[i].cap -=temp; edge[i^1].cap+=temp; flow += temp; if(maxflow==flow) break; } } } if(!flow) deep[u]=-1; return flow;}void gettu(ll mid){ s=0; t=2*n+1; memset(head,-1,sizeof(head)); cnt=0; for(int i=1;i<=n;++i) { add(s,i,a[i]); add(i,s,0); add(i+n,t,b[i]); add(t,i+n,0); } for(int i=1;i<=n;++i) { for(int j=1;j<=n;++j) { if(map[i][j]<=mid) { add(i,j+n,0x3f3f3f3f); add(j+n,i,0); } } }}int dinic(ll mid){ gettu(mid); int ans=0; while(bfs(s,t)) { ans+=dfs(s,t,0x3f3f3f3f); } if(ans==sum) return 1; return 0;}int main(){ while(~scanf("%d%d",&n,&m)) { sum=0; for(int i=1;i<=n;++i) { for(int j=1;j<=n;++j) { map[i][j]=1LL<<60; } map[i][i]=0; } for(int i=1;i<=n;++i) { scanf("%d%d",&a[i],&b[i]); sum+=a[i]; } for(int i=0;i<m;++i) { int x,y; ll w; scanf("%d%d%lld",&x,&y,&w); if(map[x][y]>w) { map[x][y]=map[y][x]=w; } } ll maxn=0; for(int i=1;i<=n;++i) { for(int j=1;j<=n;++j) { for(int k=1;k<=n;++k) { map[j][k] = min(map[j][k],map[j][i]+map[i][k]); if(map[j][k]!=(1LL<<60)) maxn=max(maxn,map[j][k]); } } } ll l=0,r=maxn+5, ans=-1,mid; while(r>=l) { mid=(l+r)/2; gettu(mid); if(dinic(mid)) { r=mid-1; ans=mid; } else l=mid+1; } printf("%lld\n",ans); }}
最小割:
Hoj:2634
做法:最大权闭合子图问题,答案为 all(权值)-最小割==最大流
#include <cstring>#include <cstdio>#include <cmath>#include <queue>#include <algorithm>typedef long long ll;using namespace std;int n,m;const int maxn=10000;struct node{ int to,next,cap;}edge[maxn<<2];int head[maxn],cnt;void add(int u,int v,int w){ edge[cnt].to=v; edge[cnt].next=head[u]; edge[cnt].cap=w; head[u]=cnt++;}int deep[maxn];int bfs(int s,int t){ memset(deep,-1,sizeof(deep)); deep[s]=0; queue<int> que; que.push(s); while(!que.empty()) { int u=que.front(); que.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(deep[v]==-1 && edge[i].cap>0) { deep[v]=deep[u]+1; que.push(v); } } } return deep[t]!=-1;}int dfs(int u,int t,int maxflow){ if(u==t || maxflow==0) return maxflow; int flow=0; for(int i=head[u];i!=-1; i=edge[i].next) { int v=edge[i].to; if(deep[v]==deep[u]+1 && edge[i].cap>0) { int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) ); if(temp) { edge[i].cap -=temp; edge[i^1].cap+=temp; flow += temp; if(maxflow==flow) break; } } } if(!flow) deep[u]=-1; return flow;}int dinic(int s,int t){ int ans=0; while(bfs(s,t)) { ans+=dfs(s,t,0x3f3f3f3f); } return ans;}int main(){ int T; scanf("%d",&T); while(T--) { scanf("%d%d",&m,&n); memset(head,-1,sizeof(head)); cnt=0; int sum=0,a; for(int i=1;i<=m;++i) { scanf("%d",&a); add(0,i,a); add(i,0,0); sum+=a; } for(int i=1;i<=n;++i) { scanf("%d",&a); add(i+m,n+m+1,a); add(n+m+1,i+m,0); } for(int i=1;i<=m;++i) { int k; scanf("%d",&k); while(k--) { scanf("%d",&a); add(i,a+m+1,0x3f3f3f3f); add(a+m+1,i,0); } } printf("%d\n",sum-dinic(0,n+m+1)); } return 0;}
Hoj2713
做法:二分图最大点权独立集;(如同黑白染色)
注意: 二分图最大点权独立集+二分图最小点权覆盖集==ALL
#include <iostream>#include <stdio.h>#include <cstring>#include <queue>using namespace std;int n,m,sum;const int maxn=3000;struct node{ int to,next,cap;}edge[1000001];int head[maxn],cnt;void add(int u,int v,int w){ edge[cnt].to=v; edge[cnt].next=head[u]; edge[cnt].cap=w; head[u]=cnt++;}int deep[maxn];int bfs(int s,int t){ memset(deep,-1,sizeof(deep)); deep[s]=0; queue<int> que; que.push(s); while(!que.empty()) { int u=que.front(); que.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(deep[v]==-1 && edge[i].cap>0) { deep[v]=deep[u]+1; que.push(v); } } } return deep[t]!=-1;}int dfs(int u,int t,int maxflow){ if(u==t || maxflow==0) return maxflow; int flow=0; for(int i=head[u];i!=-1; i=edge[i].next) { int v=edge[i].to; if(deep[v]==deep[u]+1 && edge[i].cap>0) { int temp = dfs(v,t,min(edge[i].cap,maxflow-flow) ); if(temp) { edge[i].cap -=temp; edge[i^1].cap+=temp; flow += temp; if(maxflow==flow) break; } } } if(!flow) deep[u]=-1; return flow;}int dinic(int s,int t){ int ans=0; while(bfs(s,t)) { ans+=dfs(s,t,0x3f3f3f3f); } return ans;}int in[60][60];int g[60][60];int dir[4][2]= { {1,0} , {-1,0} , {0,-1} , {0,1} };int id;bool check(int x,int y){ if(x<=0||y<=0||x>n||y>m) return 0; return 1;}int main(){ int T; scanf("%d",&T); while(T--) { memset(in,0,sizeof(in)); id=0; sum=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) { ++id; scanf("%d",&g[i][j]); in[i][j]=id; sum+=g[i][j]; } } memset(head,-1,sizeof(head)); cnt=0; int s=0,t=n*m+1; for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) { int id=in[i][j]; if((i+j)&1) { add(id,t,g[i][j]); add(t,id,0); } else { add(s,id,g[i][j]); add(id,s,0); for(int k=0;k<4;++k) { int x= i +dir[k][0]; int y= j +dir[k][1]; if(!check(x,y)) continue; add(id,in[x][y],0x3f3f3f3f); add(in[x][y],id,0); } } } } printf("%d\n",sum-dinic(s,t)); } return 0;}
阅读全文
0 0
- 2017 暑假艾教集训 day12 网络流(最大流 最小割)!
- 网络流最大流最小割算法
- 网络流最大流最小割算法
- 网络流 最小割最大流定理
- 网络的最大流最小割定理
- 网络流(最小割最大流)【POJ3469】
- 网络流(最小割最大流)【POJ3308】
- 网络流(最大流,最小割)基础入门详解
- 求最大网络流(最小割)总结
- 2017暑假七林集训day12
- 最大流/最小割
- 最大流最小割
- 最大流最小割
- 最大流最小割
- 最大流最小割
- (教你彻底理解)网络流:基本概念与算法 最大流最小割
- 【网络】网络流:最大流最小割问题
- 网络流 最小割
- 使用协调者布局CoordinatorLayout 来实现ParallaxHeaderViewPager的效果,超简单
- 毫秒,微妙级别软件定时器
- H5滚动轮播插件
- centos7 解决 Python.h:没有那个文件或目录 错误的方法
- appium测试之获取appPackage和appActivity
- 2017 暑假艾教集训 day12 网络流(最大流 最小割)!
- YYModel第三方框架
- 一步一步学MySQL-日志文件
- 共享程序集和强命名程序集
- 七周七并发模型 | 读后感
- C++11学习
- Unity 使用xLua遇到的坑
- IOC控制反转 和 DI依赖注入
- js实现的大根堆算法(基于数组的二叉树)