POJ3057_Evacuation_二分图匹配::逃生问题
来源:互联网 发布:淘宝开店教程下载 编辑:程序博客网 时间:2024/04/30 21:05
题意
给出一张地图, “D” 表示门,”.” 表示人, “X” 表示墙。人不会出现在最外面一圈,门只会出现在最外面一圈,并且一扇门一秒钟只能有一人通过。现在起火了,求所有通过门逃出地图的最短时间。如果有人逃不出去就输出 impossible。
思路
看到这个题首先想到的是最小费用流。但是,“一秒钟只能通过一个人”这个限制条件无法克服。这个问题本质上是人和门的匹配问题,因为门多了一个时间属性,所以可以用拆点法归结成一个二分图匹配的问题。
1.把每个人看成一个点,构成集合 P;把每一时刻的门看成一个点,构成集合 D。因为最大的可能时间是地图的网格总数(设想为只有一扇门,其他格都站满了人的情况),所以集合 D 的规模在可接受的范围内。
2.从每一扇门出发进行bfs,求出每个人到这扇门的最短距离。
3.对于每一扇门,利用 2 中求出来的最短时间,把能到达它的人与对应时刻的它之间连一条边。
4.依次对 D 集合中的每一个点进行匹配,一旦匹配数达到 P, 则这个点对应的时间就是需要花费的最小时间。
5.如果时间达到了上界,但匹配数依然小于 P,输出 impossible 。
需要注意的一点是,这种做法需要特判 P = 0 的情况,否则在这种情况下会输出 impossible 。
题目链接
http://poj.org/problem?id=3057
AC代码
#include<cstdio>#include<iostream>#include<cstring>#include<vector>#include<queue>using namespace std;const int maxn = 13;const int mx[4] = {0, 0, -1, 1};const int my[4] = {1, -1, 0, 0};int cas, row, col;char Map[maxn][maxn];int dis[maxn][maxn][maxn][maxn];//门到人的距离:这么存很暴力但是比较方便vector<int> G[maxn * maxn * maxn * 5];int match[maxn * maxn * maxn * 5];bool usd[maxn * maxn * maxn * 5];vector<int> dx, dy;//存门的坐标vector<int> px, py;//存人的坐标//bfs 求出门到各个人的最短距离void bfs(int x, int y, int dis[maxn][maxn]){ dis[x][y] = 0; queue<int> qx, qy; qx.push(x);qy.push(y); while(qx.size()) { x = qx.front();qx.pop(); y = qy.front();qy.pop(); for(int i= 0; i< 4; i++) { int cx = x + mx[i], cy = y + my[i]; if(cx >= 0 && cx < row && cy >= 0 && cy < col && Map[cx][cy] == '.' && dis[cx][cy] < 0) { dis[cx][cy] = dis[x][y] + 1; qx.push(cx); qy.push(cy); } } }}void add(int a, int b){ G[a].push_back(b); G[b].push_back(a);}bool dfs(int v){ usd[v] = true; for(int i= 0; i< G[v].size(); i++) { int u = G[v][i], w = match[u]; if(w < 0 || !usd[w] && dfs(w)) { match[u] = v; match[v] = u; return true; } } return false;}int main(){ cin >> cas; while(cas --) { memset(match, -1, sizeof match); memset(dis, -1, sizeof dis); dx.clear(); dy.clear(); px.clear(); py.clear(); for(int i= 0; i< maxn * maxn * maxn * 5; i++) G[i].clear(); cin >> row >> col; int m = row * col; for(int i= 0; i< row; i++) for(int j= 0; j< col; j++) cin >> Map[i][j]; for(int i= 0; i< row; i++) for(int j= 0; j< col; j++) { if(Map[i][j] == 'D') { dx.push_back(i); dy.push_back(j); bfs(i, j, dis[i][j]); } else if(Map[i][j] == '.') { px.push_back(i); py.push_back(j); } } int D = dx.size(), P = px.size(); //重要特判 if(P == 0) { cout << "0\n"; continue; } for(int i= 0; i< D; i++) for(int j= 0; j< P; j++) { //人 和 时刻门 之间连边 if(dis[dx[i]][dy[i]][px[j]][py[j]] > 0) for(int t= dis[dx[i]][dy[i]][px[j]][py[j]]; t<= m; t++) add((t - 1) * D + i, m * D + j); } int sum = 0; //枚举匹配 时刻门 for(int i= 0; i< m * D; i++) { memset(usd, false, sizeof usd); if(dfs(i)) { sum ++; if(sum == P) { cout << i / D + 1 << endl; break; } } } if(sum < P) cout << "impossible\n"; } return 0;}
阅读全文
0 0
- POJ3057_Evacuation_二分图匹配::逃生问题
- 二分图匹配问题
- HDU 3036 Escape 网格图多人逃生 网络流||二分匹配 建图技巧
- 二分图多重匹配问题
- 二分图多重匹配问题
- 二分图多重匹配问题
- 二分图多重匹配问题
- tarjan二分图匹配问题
- 二分图最大匹配问题匈牙利算法
- 二分图最大匹配问题匈牙利算法
- 关于二分图的匹配问题
- 十八、分配问题 [二分图最佳匹配]
- 二分图匹配的扩展问题
- 二分图匹配(指派问题)
- 二分图的最大匹配问题
- 二分图匹配的扩展问题
- 1393-二分图多重匹配问题
- 匈牙利算法 二分图的匹配问题
- ……
- SpringJunit 单元测试
- js的循环语句
- ajax跨域问题解决方案
- 创建型模式的讨论
- POJ3057_Evacuation_二分图匹配::逃生问题
- 微信支付开发(1) JS API支付
- 210. Course Schedule II
- dedecms获取上传图片地址(其实这个方法在哪里都可以获取)
- 每天一个python模块之Requests
- tensorflow-Variable
- redis解决(DENIED Redis is running in protected mode because prote)
- 运用assimp库进行OpenGL模型的加载与转换
- Android小技巧——为什么设置了Selector有时候会不生效