Codeforces 513F2 题解 (网络流-最大流 二分 BFS)
来源:互联网 发布:知乎提问怎么取消匿名 编辑:程序博客网 时间:2024/06/16 16:31
Scaygerboss
题目描述
在一个有障碍的网格图中,有male 个男人和female 个女人,还有一个叫BOSS的人妖(既可以当男人又可以当女人)。这些人分布在地图上,每一个cell可以同时有多个人。这些人每个人移动各需要ti 的时间,问最小需要多长时间,对于每一个人都可以和异性单独待在同一个房间里?
Sample Input
说明:
在n*m的地图上,‘.’表示一个free room ,既可以移动到或者经过的房间;‘#’表示一个障碍物单位,既不可达也不可经过。
第一行为四个整数,n,m,male,female ,分别表示地图的行数,列数,男性和女性的个数。
接下来n 行描述一个地图,表示是否可达。
接下来1行描述BOSS(人妖),x,y,t ,表示这个人所在的坐标和移动一个单位所需的时间。
接下来的male 行和female 行分别描述男人和女人,格式同上。
4 4 2 3
….
.###
####
####
2 1 1
2 1 2
2 1 2
2 1 2
2 1 2
1 1 2
Sample Output
说明:
一行一个整数,表示最少的所需时间。
2
Hint
Consider the first sample test. The scaygers are hiding on a 4 by 4 map. Scaygerboss initially resides in the cell (2, 1) and can move between cells in 1 unit of time. There are also 2 male and 3 female scaygers on the map. One of the females initially is in the cell (1, 1), and all the other scaygers are in the cell (2, 1). All the scaygers move between cells in 2 units of time. If Scaygerboss and the female scayger from the cell (1, 1) move to the cell (1, 2), and a male and a female scayger from those residing in the cell (2, 1) move to the cell (1, 1), then all the scaygers will look nerdy and lovable in 2 units of time.
———(其实就是描述描述两个单位时间怎么行动,不译了)———
- In subproblem F1 (14 points), the constraints 1 ≤ n, m ≤ 11 will hold.
- In subproblem F2 (6 points), the constraints 1 ≤ n, m ≤ 22 will hold.
题解
通过阅读题意可以得知,要求得最小的达到目标状态的时间取决于最后一个到位的人的时间,所以这就是一个求出最小的最大值的问题。
并且我们也可以看出,每个房间可以同时存在多个人,所以就可以看出这个问题的决策具有单调性:如果某一刻能达到目标状态,那么下一刻一定也能维持目标状态,如果某一刻不能达到目标状态,那么上一刻也不能达到目标状态,所以可以使用二分法。
考虑到二分答案,我们首先要思考的就是check函数如何编写。在check函数的检验中我们就已经假设了要在val(mid)时间内可达到的状态。那么回到问题来看,对于每一个人来说只要和异性之一能够在同一个格子里面相遇且每一对相遇都在不同的格子里就可以了。也就是说,必须每个人都和一个异性配对且每个格子只能有一格子对。
那么问题就转化为了网络流问题!
每一个人能和异性相遇,就可以转化为从这个人向异性流过去流量为1的流;每个格子里只有一对,就可以用拆点的方法让每一个格子的流量上界为1。对于每一个人,就应该向他可以在val时间内走到的点连一条流量为1的边。
所以说建图的模型已经显而易见了:从源点向所有的male连一条流量为1的边,从male向可达的所有点连一条流量为1的边,一个点拆出的两个点之间的流量为1,所有female可达的点向female连一条流量为1的边,最后由所有的female连向汇点。
为了保证时间复杂度,在二分之前应该从每一个人作为起点开始bfs,处理出对于每一个点的距离,如果某个人到点的距离*这个人移动一单位的时间<=mid,就把这条边加进去。
注意:
对于INF的处理,如果INF设得比较大一定要特殊判断#障碍点。因为t很大,乘上一个INF很有可能爆int变成负数导致答案变小。这个地方我错了一次要注意一点。
还有一点就是答案的上界超过了int,记得二分的时候用longlong。
代码
先粘为快!
#include <cstdio>#include <iostream>#include <cmath>#include <algorithm>#include <queue>using namespace std;//#define debugconst int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};const int maxn=25;const int INF=int(1e9)+7;int n,m,male,female;char Map[maxn][maxn];struct Node { int x,y; int speed; long long dis[maxn][maxn]; bool used[maxn][maxn]; queue<int> quex,quey; void read() { scanf("%d%d%d",&x,&y,&speed); return; } void pre_bfs() { for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) dis[i][j]=INF,used[i][j]=false; while(quex.size()) quex.pop(); while(quey.size()) quey.pop(); dis[x][y]=0; used[x][y]=true; quex.push(x),quey.push(y); while(quex.size()) { int a=quex.front(),b=quey.front(); quex.pop(),quey.pop(); used[a][b]=false; for(int k=0;k<4;k++) { int nx=a+dir[k][0],ny=b+dir[k][1]; if(Map[nx][ny]=='#') continue; if(nx<1 || ny<1 || nx>n || ny>m || dis[nx][ny]<=dis[a][b]+1) continue; dis[nx][ny]=dis[a][b]+1; if(!used[nx][ny]) { used[nx][ny]=true; quex.push(nx), quey.push(ny); } } } return; }}node1[maxn*maxn], node2[maxn*maxn];void read() { scanf("%d%d%d%d",&n,&m,&male,&female); for(int i=1;i<=n;i++) scanf("%s",Map[i]+1); Node boss; boss.read(); for(int i=1;i<=male;i++) node1[i].read(); for(int i=1;i<=female;i++) node2[i].read(); if(male-female==1) node2[++female]=boss; else if(female-male==1) node1[++male]=boss; else { printf("-1\n"); exit(0); } return;}void init() { for(int i=1;i<=male;i++) node1[i].pre_bfs(); for(int i=1;i<=female;i++) node2[i].pre_bfs(); return;}const int maxd=int(1e4)+7;const int maxe=int(1e6)+7;int tot=0;int head[maxd];int S,T;#define perm(k) (S+k)#define perf(k) (perm(male)+k)#define posin(i,j) (perf(female)+(i-1)*m+j)#define posout(i,j) (posin(n,m)+(i-1)*m+j)struct Edge { int from,to,cap,next; Edge() {} Edge(int x,int y,int c,int nx):from(x),to(y),cap(c),next(nx) {}}eage[maxe*2];void add(int x,int y,int c) { eage[tot]=Edge(x,y,c,head[x]), head[x]=tot++; eage[tot]=Edge(y,x,0,head[y]), head[y]=tot++; return;}int dis[maxd];bool used[maxd];queue<int> que;bool bfs() { for(int i=S;i<=T;i++) dis[i]=INF,used[i]=false; while(que.size()) que.pop(); que.push(S); used[S]=true; dis[S]=0; while(que.size()) { int u=que.front(); que.pop(); used[u]=false; for(int i=head[u];~i;i=eage[i].next) if(dis[eage[i].to]>dis[u]+1 && eage[i].cap) { int v=eage[i].to; dis[v]=dis[u]+1; if(!used[v]) { used[v]=true; que.push(v); } } } return (dis[T]<INF);}int dfs(int u,int flow) { if(u==T || !flow) return flow; int ret=0; for(int i=head[u];~i;i=eage[i].next) if(eage[i].cap && dis[eage[i].to]==dis[u]+1) { int v=eage[i].to; int newf=dfs(v,min(flow,eage[i].cap)); eage[i].cap-=newf; eage[i^1].cap+=newf; ret+=newf; flow-=newf; if(!flow) break; } if(!ret) dis[u]=-1; return ret;}int dinic() { int res=0; while(bfs()) res+=dfs(S,INF); return res;}void build(long long val) { S=1,T=posout(n,m)+1; for(int i=S;i<=T;i++) head[i]=-1; tot=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) add(posin(i,j),posout(i,j),1); for(int i=1;i<=male;i++) { add(S,perm(i),1); for(int x=1;x<=n;x++) for(int y=1;y<=m;y++) if(node1[i].dis[x][y]!=INF && node1[i].dis[x][y]*node1[i].speed<=val) add(perm(i),posin(x,y),1); } for(int i=1;i<=female;i++) { add(perf(i),T,1); for(int x=1;x<=n;x++) for(int y=1;y<=m;y++) if(node2[i].dis[x][y]!=INF && node2[i].dis[x][y]*node2[i].speed<=val) add(posout(x,y),perf(i),1); } return;}bool check(long long val) { build(val); return (dinic()==male);}int main() { read(); init(); long long l=0,r=(1ll<<40),res=-1; while(l<=r) { long long mid=(l+r)>>1; if(check(mid)) r=mid-1,res=mid; else l=mid+1; } printf("%I64d\n",res==INF?-1:res); return 0;}
- Codeforces 513F2 题解 (网络流-最大流 二分 BFS)
- Codeforces 513F1 513F2 Scaygerboss 网络流
- bzoj 1189 二分+BFS+网络最大流
- Codeforces 316C2 题解 (网络流-最小费用最大流)
- [BZOJ1189][HNOI2007]紧急疏散evacuate(bfs+二分+最大流)
- hdu3468 最大流/二分匹配+BFS
- BZOJ3993 星际战争 题解(二分+最大流)
- Codeforces 808F 网络流最小割(二分图最大点权独立集) 解题报告
- CodeForces 589F Gourmet and Banquet(二分 + 最大流)
- Codeforces--653D--Delivery Bears(二分+最大流)
- codeforces 653D (二分 最大流)
- [扫描线 二分图最大匹配 线段树优化网络流] Codeforces 793G Tinkoff Challenge
- POJ 1273 网络流最大流 题解
- BZOJ 1189 紧急疏散evacuate 二分+BFS+最大流
- 【HNOI2007】紧急疏散EVACUATE BFS+二分答案+最大流
- 【二分+有源汇上下界最大流】ZOJ3496[Assignment]题解
- 【二分+最大流Dinic】BZOJ1305(CQOI2009)[dance跳舞]题解
- 【网络流24题】试题库(二分图+最大流)
- 关于指针的一点知识和九度oj1518
- 经典算法题:大数据处理常见算法题
- 使用ocilib库访问oracle数据库
- springmvc常用注解标签详解
- SignalR简介
- Codeforces 513F2 题解 (网络流-最大流 二分 BFS)
- 《第一行代码》学习笔记
- Kth Largest Element in an Array(数组中第K大元素)
- fdisk 命令与parted 命令的区别
- Linux学习之——/etc/sysconfig目录
- jquery 获取多个具有相同name的checkbox的选中的值
- 从RecyclerView、NestedScrollView源码分析嵌套滑动异常
- input标签内发生变化进行监听
- Struts2总结---OGNL表达式的基本语法和用法 (8)