题意:

给出了一个 Y∗XY*XY∗X 的地图,在地图的四个边缘有门,用 ′D′'D'′D′ 表示,′X′'X'′X′ 表示障碍物即不能走,′.′'.'′.′表示这个位置初始有一个人,现在地图中的所有人要逃出门外,每个 ′.′'.'′.′ 这个点可以站好多人,但是出门的时候只能一个一个出,每个人移动一格的时间为 111,问最少需要多少时间,所有人可以撤出场地。如果不能撤出,输出 impossibleimpossibleimpossible 。


思路:

因为是最少的时间,所以一开始想到的是最小割和最小费用最大流,然后发现均无法解决这个问题,因为难以解决每个时间每个门只能被经过一次这个问题。

后来发现我们可以对每一个时刻的门分别建点,然后使这个门的容量为 111,因此就可以满足每个时刻每个门只能出去一个人这个条件。

但是如果对门的所有时刻都建点的话,那么无疑跑出来的结果是不对的,即我们现在只能验证当前每一个时刻上限的情况下,所有人能不能出来。因此发现这个题的答案,即所需要的时间是单调的,因此可以进行二分答案。二分所有人出门的时间,然后用最大流建图来验证。

当二分的时间为 xxx 时,则对每个门都建 xxx 个点,然后每个人到达这个门所需的时间如果为 yyy 的话,则将这个人与这个门所有 >=y>=y>=y 的时刻连边。至此即可完成本题。


代码:

//bzoj 3262
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
#define rep(i,a,b) for(int i = a;i <= b;i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
using namespace std;
const int inf = 1<<29,N = 1e5+100,M = 5*1e6+100;  //处理1e4-1e5规模的网络struct Edge{ int to,next,v;
}e[M];
int n,m,s,t;  //顶点个数 边数 源点 汇点
int head[N],tot,dis[N];
queue<int> q;
char mp[20][20];
int numdoor,mandoor[200][200],numman,hp[200],vis[300];
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};void bbfs(int x)
{// printf("x:%d\n",x);queue<pair<int,int> > qp;while(qp.size()) qp.pop();memset(vis,0,sizeof vis);vis[x] = 1;qp.push(make_pair(x,0));while(qp.size()){int xx = qp.front().first, dist = qp.front().second;int yy = xx%m;qp.pop();xx = xx/m+1;rep(i,0,3){int xxx = xx+dir[i][0], yyy = yy+dir[i][1];int tp = (xxx-1)*m+yyy;if(xxx < 1 || xxx > n || yyy < 1 || yyy > m || mp[xxx][yyy] == 'X') continue;if(vis[tp]) continue;if(mp[xxx][yyy] == 'D'){// printf("oops!\n");// LOG2("x",x,"tp",tp);// LOG1("dist",dist);mandoor[hp[x]][hp[tp]] = dist+1;continue;}vis[tp] = 1;qp.push(make_pair(tp,dist+1));}}
}void init_solve()
{memset(mandoor,0,sizeof mandoor);numman = numdoor = 0;memset(hp,0,sizeof hp);rep(i,1,n)rep(j,1,m)if(mp[i][j] == '.') hp[(i-1)*m+j] = ++numman;else if(mp[i][j] == 'D') hp[(i-1)*m+j] = ++numdoor;rep(i,1,n)rep(j,1,m)if(mp[i][j] == '.'){// printf("i:%d,j:%d\n",i,j);bbfs((i-1)*m+j);}
}void init()   //千万别忘了初始化!
{tot = 1; memset(head,0,sizeof head);  //点的编号是2~n,因为2^1 = 3, 3^1 = 2;  符合后续代码的操作
}void add(int x,int y,int v)
{e[++tot].to = y; e[tot].next = head[x]; e[tot].v = v; head[x] = tot;e[++tot].to = x; e[tot].next = head[y]; e[tot].v = 0; head[y] = tot;  //反向边与正向边的流量之和为v
}bool bfs()
{memset(dis,0,sizeof dis);while(!q.empty()) q.pop();q.push(s); dis[s] = 1;while(!q.empty()){int x = q.front(); q.pop();for(int i = head[x];i;i = e[i].next){if(e[i].v && !dis[e[i].to]){q.push(e[i].to);dis[e[i].to] = dis[x]+1;if(e[i].to == t) return 1;  //找到一条路就return }}}return 0;
}int dinic(int x,int flow) //找增广路
{   if(x == t) return flow;int rest = flow,k;  //rest为输入的流量 for(int i = head[x];i && rest; i = e[i].next){if(e[i].v && dis[e[i].to] == dis[x]+1){k = dinic(e[i].to,min(rest,e[i].v));if(!k) dis[e[i].to] = 0;  //剪枝,去掉增广完毕的点 e[i].v -= k;e[i^1].v += k;  //反向边加上flow,相当于我们可以反悔从这条路流过 rest -= k; //k为能够被送出去的流量 }}return flow-rest;  //总共被送出去了多少流量
}int solve()
{int flow = 0,maxflow = 0;while(bfs())while(flow = dinic(s,inf)) maxflow += flow;return maxflow;
}void mainsolve()
{int l = 1, r = 200, ans = -1;while(l <= r){int mid = (l+r)>>1;init();s = 1, t = 1+numman+mid*numdoor+1;rep(i,1,numman) add(s,i+1,1);rep(i,1,numdoor)rep(j,1,mid) add(1+numman+(i-1)*mid+j,t,1);rep(i,1,numman)rep(j,1,numdoor)if(mandoor[i][j] <= mid && mandoor[i][j])rep(k,mandoor[i][j],mid) add(1+i,1+numman+(j-1)*mid+k,1);if(solve() == numman) r = mid-1, ans = mid;else l = mid+1;}if(ans == -1) printf("impossible\n");else printf("%d\n",ans);
}int main()
{int _; scanf("%d",&_);while(_--){scanf("%d%d",&n,&m);rep(i,1,n) scanf("%s",mp[i]+1);init_solve();mainsolve();}return 0;
}

【POJ 3057】Evacuation【最大流+二分】相关推荐

  1. POJ 3057 Evacuation(二分匹配)

    分析: 这是一个时间和门的二元组(t,d)和人p匹配的问题,当我们固定d0时,(t,d0)匹配的人数和t具有单调性. t增加看成是多增加了边就行了,所以bfs处理出p到每个d的最短时间,然后把(t,d ...

  2. 【POJ 3273】 Monthly Expense (二分)

    [POJ 3273] Monthly Expense (二分) 一个农民有块地 他列了个计划表 每天要花多少钱管理 但他想用m个月来管理 就想把这个计划表切割成m个月来完毕 想知道每一个月最少花费多少 ...

  3. POJ.3281 dining 最大流+拆点

    POJ.3281 dining 最大流+拆点 思路清晰为啥一直WA呢 #include <iostream> #include <cstring> #include <v ...

  4. POJ 3258 River Hopscotch (二分)

    题目地址:POJ 3258 水题.二分距离,判断是否可行.需要注意的是最后一个,因为最后一个是没法移除的,所以还要倒着判断一下. 代码如下: #include <iostream> #in ...

  5. POJ 2112 Optimal Milking(二分+最大流)

    POJ 2112 Optimal Milking 题目链接 题意:给定一些机器和奶牛,在给定距离矩阵,(不在对角线上为0的值代表不可达),每一个机器能容纳m个奶牛.问全部奶牛都能挤上奶,那么走的距离最 ...

  6. POJ 2455 Secret Milking Machine 二分枚举 + 最大流

    题目:http://poj.org/problem?id=2455 题意:给定一张无向图,有n个节点p条边,要求在图中从1到n找到t条路径,并且使这t条路径中的最长边最小,输出这个最小的最长边 思路: ...

  7. POJ 2391 Ombrophobic Bovines ★(Floyd+二分+拆点+最大流)

    [题意]有n块草地,一些奶牛在草地上吃草,草地间有m条路,一些草地上有避雨点,每个避雨点能容纳的奶牛是有限的,给出通过每条路的时间,问最少需要多少时间能让所有奶牛进入一个避雨点. 和POJ2112很类 ...

  8. POJ 2455Secret Milking Machine(二分+网络流之最大流)

    题目地址:POJ2455 手残真浪费时间啊..又拖到了今天才找出了错误..每晚两道题不知不觉又变回了每晚一道题...sad.. 第一次在isap中忘记调用bfs,第二次则是遍历的时候竟然是从1開始遍历 ...

  9. poj 3189 Steady Cow Assignment(二分+最大流)

    题意:N头牛(1000),B个农场(20),每个农场可以容纳一定数量的牛. 每头牛对每个农场都有一个排名(排名从1~B).每头牛都会在B个农场中的某一个,这头牛的高兴程度是它对这个农场的排名.为了使每 ...

  10. poj 2455 Secret Milking Machine(二分枚举+最大流)

    题意: 题意:FJ有N块地,这些地之间有P条双向路,每条路的都有固定的长度l.现在要你找出从第1块地到第n块地的T条不同路径,每条路径上的路不能与先前的路径重复,问这些路径中的最长路的最小是多少. 思 ...

最新文章

  1. list、tuple、set、dict 四大数据结构
  2. 狂风暴雨——电闪雷鸣篇:数据流层核心思想揭秘
  3. 计算机基础知识应用文档,计算机基础知识与应用
  4. springboot 自动配置
  5. 成功解决FileNotFoundError: [Errno 2] No such file or directory: '/home/bai/Myprojects/Tfexamples/data/kn
  6. 【网络安全】如何使用keimpx检测网络环境中的有效凭证
  7. 安装错误 服务尚未启动_原创 | 西门子300软件安装出错处理大全
  8. 2017.10.13java上机出现中的问题
  9. vue中使用cookies和crypto-js实现记住密码和加密
  10. python部落稿酬_Python之父考虑重构Python解释器
  11. SQL SERVER 2012 只能识别20个CPU的问题
  12. cad边长提取lisp_用lisp怎么提取cad中文字-内容-*通用符匹配(值 :设定)生成excel文件...
  13. 微信端和手机qq浏览器输入框不能输入汉字
  14. 关于keil编译显示Flash Download failed -Could not load file xxxx.axf
  15. banner中居中的page显示完全,其余显示百分之20--仿网易云首页轮播图
  16. 【兴趣】日语(2021年3月24~)
  17. 用PHP实现MD5算法
  18. 2021年西式面点师(高级)新版试题及涵盖考试最全题库免费练习
  19. Windows 组策略修改 之 初始化文件 %windir%\inf\defltbase.inf
  20. 购买的wemall6.0源码商城系统分享,百度云盘易失效,速取

热门文章

  1. 总结命令----tar
  2. 怎么设置Linux swap分区?方法教程
  3. 11月7日简单标签与Listener培训日记
  4. layui和js实现二级联动
  5. 百元百鸡 //构造结构体变量
  6. python 累加_对Python实现累加函数的方法详解
  7. Android10定位无法选择,Android 10不能使用uiautomatorviewer定位元素的终极解决方法
  8. 五大列级庄_酒庄拉菲古堡Chateau Lafite Rothschild, 波尔多五大一级庄之首
  9. python文本字符串比对_[Python] 利用HTML页面查看字符串差异
  10. java找链表中最小值_算法图解:如何找出栈中的最小值?