最大流,二分法,拆点法(士兵移动 uva 12264)
来源:互联网 发布:差评师数据设置 编辑:程序博客网 时间:2024/05/17 04:37
给n个点的无权无向图(n<=100),每个点有一个非负数ai。若ai==0则此点归敌方所有,若ai>0则此点归你且上面有ai个属于你的士兵。保证至少有一个属于你的点与敌方的点相邻。你可以让你的每个士兵最多移动一次,每次可以待在原地或者去到相邻的属于你的领地,但每个点至少要留1各士兵,使得最薄弱的关口尽量坚固。关口是指与敌方点相邻的点,薄弱与坚固分别指兵少与兵多。
我参考了这篇博客上的一些讲解。http://www.voidcn.com/blog/a197p/article/p-4252874.html
思路:把每个点拆成两个点,一个入度,一个出度,入度向自己的和每个相邻的点的出度连一条边,容量是ai,每个点出度连一条边到汇点,容量为1,那些与敌人相邻的点再多连一条边到汇点,容量是二分的值,我们只需要二分这个值,跑一下网络流,如果满流,表示可以,否则不行。
本篇通过第二个样例讲解思路,下图是第二个样例的建图结果。
敌方的点不需要参与建图,因此图中没有6,7号点。
INF指无穷,mid指二分的中值。
Q:为何需要拆点?
A:我们希望通过拆点来实现每个士兵最多移动一次。下图中每个INF的边都是士兵移动的边,观察后可以发现如此建图士兵只能从入点移动到另一个点的出点,因此最多只能移动一次。(根据题意每次最远移动到相邻的点)
Q:为何出点需要连一条容量为1的边到汇点?
A:为了保证己方的点至少有1个士兵,观察下图 1出 与 2出 满流时说明1和2点至少1个人。
Q:为何要二分?
A:我们要让最薄弱的关口尽量坚固,就得使关口的士兵分配得尽量均匀,然而最大流的算法不能保证分配均匀,我们只好一个个的试,满载就放宽条件,不满载就严加条件,直到试出可行的最大解。
以下渣代码
#include<stdio.h>#include<vector>#include<queue>#include<string.h>#define maxn 250#define INF 0X3F3F3F3Fusing namespace std;int N;int A[maxn];char MAP[maxn][maxn];bool ib[maxn];struct Edge{ int from,to,cap,flow; Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}};struct EdmondsKarp{ int n,m; vector<Edge>edges; vector<int>G[maxn]; int a[maxn]; int p[maxn]; void init(int n) { this->n=n; for(int i=0;i<n;i++) G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap) { edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0)); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } int Maxflow(int s,int t) { int flow=0; for(;;) { memset(a,0,sizeof(a)); queue<int>Q; Q.push(s); a[s]=INF; while(!Q.empty()) { int x=Q.front();Q.pop(); for(unsigned int i=0;i<G[x].size();i++) { Edge& e=edges[G[x][i]]; if(!a[e.to]&&e.cap>e.flow) { p[e.to]=G[x][i]; a[e.to]=min(a[x],e.cap-e.flow); Q.push(e.to); } } if(a[t]) break; } if(!a[t]) break; for(int u=t;u!=s;u=edges[p[u]].from) { edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; } flow+=a[t]; } return flow; } int Build(int val) { int ans=0; memset(ib,0,sizeof(ib)); init(2*N+2); for(int i=1;i<=N;i++) { if(!A[i]) continue; AddEdge(0,i,A[i]); AddEdge(i,i+N,A[i]); for(int j=1;j<=N;j++) if(MAP[i][j]=='Y') { if(!A[j]) ib[i]=true; else AddEdge(i,j+N,INF); } } for(int i=1;i<=N;i++) if(ib[i]) {AddEdge(i+N,n-1,val);ans+=val;} else if(A[i]){AddEdge(i+N,n-1,1);ans++;}; return ans; } void solve() { int a,b,ans; int l=0,r=10010; while(l<r) { int mid=(l+r)>>1; a=Build(mid); b=Maxflow(0,n-1); if(a==b) { l=mid+1; ans=mid; } else r=mid; } printf("%d\n",ans); }};int main(){ int t; scanf("%d",&t); while(t--) { scanf("%d",&N); for(int i=1;i<=N;i++) scanf("%d",&A[i]); for(int i=1;i<=N;i++) scanf("%s",MAP[i]+1); EdmondsKarp EK; EK.solve(); } return 0;}
- 最大流,二分法,拆点法(士兵移动 uva 12264)
- Risk uva 12264(最大流,二分法,拆点法)
- [BZOJ1458]士兵占领(最大流)
- 【bzoj 1458】士兵占领(最大流)
- 【bzoj 1458】士兵占领(最大流)
- bzoj1458 士兵占领(最大流)
- poj1723(士兵移动)
- BZOJ1458 士兵占领 最大流
- 【bzoj1458】士兵占领 最大流
- 【BZOJ1458】士兵占领【最大流】
- BZOJ1458: 士兵占领 最大流
- 【bzoj1458】士兵占领 最大流
- BZOJ1458 士兵占领-最大流
- [bzoj1458]士兵占领 最大流
- 【bzoj3993】【SDOI2015】【二分法+最大流】
- poj 2112 最大流+二分法
- uva - 12097 - Pie(二分法)
- UVA 714-抄书(二分法)
- 使用Eclipse的几个必须掌握的快捷方式
- install the brew in mac
- Redis和Memcached的区别
- 创建第一个Android开发工具自带的模拟器
- 13. Roman to Integer--LeetCode Record
- 最大流,二分法,拆点法(士兵移动 uva 12264)
- 第十一次课总结及作业
- 5个数据科学相关的Python库
- java 集合中自定义对象的几种排序方法
- C 语言 指针和数组的结合
- unity中实现 幸运转轮
- 【慢速学数据结构】集合(并查集)篇
- hdu 1232 畅通工程并查集版
- c 使用检讨循环产生的图案