二分+二分图匹配+BFS


题意:

墙壁“X”,空区域(都是人)“.”, 门“D”。

人向门移动通过时视为逃脱,门每秒能出去一个人,人可以上下左右移动,墙阻止移动。

求最优移动方案下,最后一个人逃脱的最短时间。如果有人无法安全逃脱(比如被墙围困住),则输出“impossible”。
 
解法1:
以每个门为起点可以通过BFS来算出每个人逃离的最短路。
二分答案,判断所有的人能否在时间T内逃脱。
考虑某一个门,如果能在时间t从该门逃脱的人,应该是距离该门t以内的人,并且其中只有一人能够从该门逃脱。
每个时间和门的二元组,都能确定一个对应的能够从中逃脱的人的集合,而通过计算这个二元组和人组成的二分图的最大匹配数,我们就能判断所有人是否逃脱。
会T。
 const int dx[] = {, , , -};
const int dy[] = {, , -, }; int X, Y;
char field[MAXN][MAXN]; vector<int> dX, dY;
vector<int> pX, pY;
int dist[MAXN][MAXN][MAXN][MAXN]; const int MAXV = ;
int V; //顶点数
vector<int> G[MAXV]; //图的邻接表表示
int match[MAXV]; //所匹配的定点
bool used[MAXV]; // DFS中用到的访问标记 //添加无向边,注意顶点编号从0开始
void add_edge(int u, int v) {
G[u].push_back(v);
G[v].push_back(u);
} //通过DFS寻找增广路
bool dfs(int v) {
used[v] = true;
for (int i = ; i < G[v].size(); i++) {
int u = G[v][i], w = match[u];
if (w < || !used[w] && dfs(w)) {
match[v] = u;
match[u] = v;
return true;
}
}
return false;
} //二分图最大匹配,返回最大匹配数
int Bipartite_Matching() {
int res = ;
memset(match, -, sizeof(match));
for (int v = ; v < V; v++) {
if (match[v] < ) {
memset(used, , sizeof(used));
if (dfs(v)) {
res++;
}
}
}
return res;
} // 二分,这一点非常精妙
bool C(int t) {
// 0~d-1 时间1跑掉的人
// d~2d-1 时间2跑掉的人
// (t-1)d~td-1 时间t跑掉的人
// td~td+p-1 人
int d = dX.size(), p = pY.size();
V = t * d + p;
REP(i, , V) G[i].clear();
REP(i, , d) REP(j, , p) {
int o = dist[dX[i]][dY[i]][pX[j]][pY[j]];
if (o >= ) {
REP(k, o, t + )
add_edge((k - ) * d + i, t * d + j);
}
}
return Bipartite_Matching() == p;
} void bfs(int x, int y, int d[MAXN][MAXN]) {
queue<int> qx, qy;
d[x][y] = ;
qx.push(x);
qy.push(y);
while (!qx.empty()) {
x = qx.front(), qx.pop();
y = qy.front(), qy.pop();
REP(i, , ) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= && nx < X && ny >= && ny < Y &&
field[nx][ny] == '.' && d[nx][ny] < ) {
d[nx][ny] = d[x][y] + ;
qx.push(nx);
qy.push(ny);
}
}
}
} void solve() {
int n = X * Y; //跑最短路
REP(i, , dX.size()) bfs(dX[i], dY[i], dist[dX[i]][dY[i]]); //最短路
int lb = -, ub = n + ;
while (ub - lb > ) {
int mid = (ub + lb) / ;
C(mid) ? ub = mid : lb = mid;
} if (ub > n) {
printf("impossibe\n");
} else {
printf("%d\n", ub);
}
} int main() {
#ifndef ONLINE_JUDGE
// freopen("input.txt", "r", stdin);
#endif // !ONLINE_JUDGE
int T = READ();
while (T--) {
dX.clear(), dY.clear();
pX.clear(), pY.clear();
CLR(field), SET(dist);
X = READ();
Y = READ();
REP(i, , X) cin >> field[i];
REP(i, , X) REP(j, , Y) {
if (field[i][j] == 'D') {
dX.push_back(i);
dY.push_back(j);
} else if (field[i][j] == '.') {
pX.push_back(i);
pY.push_back(j);
}
}
solve();
}
return ;
}

解法2:

在上述解法下,重复的操作是每次二分都会计算一遍匹配,所以T,那么当T增加时,根据增广路的性质,我们只需要不断增加T,每次加1,就可以找出答案。

这个其实现在也不怎么看懂。

下面是不同的地方,一样的没放上来

 void solve() {
int n = X * Y; //跑最短路
REP(i, , dX.size()) bfs(dX[i], dY[i], dist[dX[i]][dY[i]]); // 加边
int d = dX.size(), p = pX.size();
V = X * Y * d + p;
for (int v = ; v < V; ++v) G[v].clear();
REP(i, , d) REP(j, , p) {
int o = dist[dX[i]][dY[i]][pX[j]][pY[j]];
if (o >= ) REP(k, o, n + ) add_edge((k - ) * d + i, n * d + j);
} // 匹配
if (p == ) {
printf("0\n");
return;
}
int num = ; // 匹配数
memset(match, -, sizeof(match));
for (int v = ; v < n * d; v++) {
// n*d是节点总数,每个门一个,把所有情况都跑一遍
memset(used, , sizeof(used));
if (dfs(v)) {
if (++num == p) {
printf("%d\n", v / d + );
return;
}
}
}
printf("impossible\n");
}

(好题)POJ3057的更多相关文章

  1. POJ3057 Evacuation 二分图匹配+最短路

    POJ3057 Evacuation 二分图匹配+最短路 题目描述 Fires can be disastrous, especially when a fire breaks out in a ro ...

  2. java基础集合经典训练题

    第一题:要求产生10个随机的字符串,每一个字符串互相不重复,每一个字符串中组成的字符(a-zA-Z0-9)也不相同,每个字符串长度为10; 分析:*1.看到这个题目,或许你脑海中会想到很多方法,比如判 ...

  3. 【Java每日一题】20170106

    20170105问题解析请点击今日问题下方的"[Java每日一题]20170106"查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; ...

  4. 【Java每日一题】20170105

    20170104问题解析请点击今日问题下方的"[Java每日一题]20170105"查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; ...

  5. 【Java每日一题】20170104

    20170103问题解析请点击今日问题下方的"[Java每日一题]20170104"查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; ...

  6. 【Java每日一题】20170103

    20161230问题解析请点击今日问题下方的"[Java每日一题]20170103"查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; ...

  7. SQL面试笔试经典题(Part 1)

    本文是在Cat Qi的原贴的基础之上,经本人逐题分别在MySql数据库中实现的笔记,持续更新... 参考原贴:http://www.cnblogs.com/qixuejia/p/3637735.htm ...

  8. 刷LeetCode的正确姿势——第1、125题

    最近刷LeetCode比较频繁,就购买了官方的参考电子书 (CleanCodeHandbook),里面有题目的解析和范例源代码,可以省去非常多寻找免费经验分享内容和整理这些资料的时间.惊喜的是,里面的 ...

  9. AWS的SysOps认证考试样题解析

    刚考过了AWS的developer认证,顺手做了一下SysOps的样题.以下是题目和答案. When working with Amazon RDS, by default AWS is respon ...

随机推荐

  1. 面试必备!Java核心技术100+面试题

    一线互联网公司工作了几年,我作为求职者参加了不少面试,也作为面试官面试了很多同学,整理这份面试指南,一方面是帮助大家更好的准备面试,有的放矢,另一方面也是对自己知识框架做一个体系化的梳理. 这篇文章梳 ...

  2. C语言寒假大作战01

    问题 回答 这个作业属于哪个课程 2019软件四班C语言寒假作业大作战 这个作业要求在哪里 作业要求 我在这个课程的目标是 gitee 与 git基础命令学习与使用 这个作业在那个具体方面帮助我实现目 ...

  3. [总结]ACM模拟总结

    1.心态一定要稳,千万不要慌. 2.内部交流要多点,说不定就讨论出有用的性质了. 3.题目细节一定要想清楚. 4.一道题绝对不能让多个人来写. 5.英语要好好学.

  4. 什么是Druid

    一.Druid是什么 Druid 单词来源于西方古罗马的神话人物,中文常常翻译成德鲁伊. 玩过魔兽世界,暗黑破坏神,Dota,炉石传说,Dota自走棋的朋友,对这个词一定不陌生. 本文中所介绍的Dru ...

  5. 科普文,搭建python开发环境

    Python简介!首先,是一门面向对象的程序设计语言,先说3个优点!1.有条理,简单,易学,易用.2.强大!可以把其他编程语言制作的模块利用起来.3.拥有丰富的库.Python作为高级编程语言,拥有的 ...

  6. GO异常 | runnerw.exe: CreateProcess failed with error 21

    背景 今天创建了一个GO项目,写了几行代码 package chapter1 import "fmt" func main() { fmt.Println("hello ...

  7. 1、OSI参考模型

    网络的层次模型:Core layer (核心层):高速转发,不建议做策略  Distribution layer (分布层,汇聚层):基于策略连接(路由控制,安全策略)Access layer (接入 ...

  8. 全局对象的构造函数会在main函数之前执行?

    #include <iostream> using namespace std; class CTest { public: CTest() { cout << "构 ...

  9. Codeforces 977D Divide by three, multiply by two(拓扑排序)

      Polycarp likes to play with numbers. He takes some integer number xx, writes it down on the board, ...

  10. Dubbo 服务 IP 注册错误踩坑经历

    个人博客地址 studyidea.cn,点击查看更多原创文章 踩坑 公司最近新建一个机房,需要将现有系统同步部署到新机房,部署完成之后,两地机房同时对提供服务.系统架构如下图: 这个系统当前对外采用 ...