二分+二分图匹配+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. basic-pentesting-1 靶机提权

    原文地址:https://www.payload.com.cn/   basic-pentesting-1 下载地址: https://www.vulnhub.com/entry/basic-pent ...

  2. FileZilla 报错“the server's certificate is unknown”

    FileZilla 是非常好用的一款FTP SFTP 管理工具. 但是filezilla会报错“the server's certificate is unknown” 并且会在window中看到以下 ...

  3. python中[-1]、[:-1]、[::-1]、[n::-1]使用方法

    import numpy as np a=np.random.rand(5) print(a) [ 0.64061262 0.8451399 0.965673 0.89256687 0.4851874 ...

  4. 什么是LakeHouse?

    1. 引入 在Databricks的过去几年中,我们看到了一种新的数据管理范式,该范式出现在许多客户和案例中:LakeHouse.在这篇文章中,我们将描述这种新范式及其相对于先前方案的优势. 数据仓库 ...

  5. Mondriaan's Dream 轮廓线DP 状压

    Mondriaan's Dream 题目链接 Problem Description Squares and rectangles fascinated the famous Dutch painte ...

  6. php7 mongodb 扩展windows 安装

    1. 打开phpinfo 查看 nts(非线程) 还是 ts (线程),然后查看操作位数 注: 86 等于 32 位  2. 下载对应的版本的php_mongodb.dll 文件 下载链接: pecl ...

  7. JVM性能优化系列-(3) 虚拟机执行子系统

    3. 虚拟机执行子系统 3.1 Java跨平台的基础 Java刚诞生的宣传口号:一次编写,到处运行(Write Once, Run Anywhere),其中字节码是构成平台无关的基石,也是语言无关性的 ...

  8. 程序为什么开头总是PUSH EBP

    因为对堆栈的操作寄存器有EBP和ESP两个.EBP是堆栈的基址,ESP一直指向栈顶(只要有PUSH动作,ESP就自动减小,栈的生长方向从大往小,不需要手动改变ESP.)所以要压入EBP,然后再用EBP ...

  9. 机器学习(ML)十之CNN

    CNN-二维卷积层 卷积神经网络(convolutional neural network)是含有卷积层(convolutional layer)的神经网络.卷积神经网络均使用最常见的二维卷积层.它有 ...

  10. Go语言实现:【剑指offer】旋转数组的最小数字

    该题目来源于牛客网<剑指offer>专题. 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3, ...