题目大意:紧急疏散。有一张地图,‘.’表示人,‘D’表示门,人需要走曼哈顿距离的单位时间才1能到达门。一个门一个时刻只能通过一个人。求多长时间能疏散完毕。
思路:二分答案+最大流满流判定。先BFS处理出每个人与门的距离。二分最小时间,然后连边。S向每个人连流量为1的边,每个人向二分的时间之内能到达的门连流量为1的边。每个门向T连流量为t的边。然后最大流判定是否满流。
(数组大小我是瞎开的,写代码的时候要算好了在开!)
CODE:
#include
#include
#include
#include
#include
#define MAX 10010
#define S 0
#define T 5000
#define INF 0x7f7f7f7f
using namespace std;
const int dx[] = {0,0,0,1,-1};
const int dy[] = {0,1,-1,0,0};
struct Door{
int x,y;
Door(int _,int __):x(_),y(__) {}
Door() {}
}door[MAX];
struct Empty{
int x,y;
Empty(int _,int __):x(_),y(__) {}
Empty() {}
}person[MAX];
struct Status{
int x,y;
int length;
Status(int _,int __,int ___)
:x(_),y(__),length(___) {}
Status() {}
};
int m,n;
int doors,persons;
char src[30][30];
int num[30][30],dis[MAX][410];
bool v[30][30];
int head[MAX],total;
int _next[2000000],aim[2000000],flow[2000000];
int deep[MAX];
inline void BFS(int p);
inline void MakeGraph(int t);
inline void Initialize();
inline void Add(int x,int y,int f);
bool BFS();
int Dinic(int x,int f);
int main()
{
cin >> m >> n;
for(int i = 1;i <= m; ++i) {
scanf("%s",src[i] + 1);
for(int j = 1;j <= n; ++j) {
if(src[i][j] == 'D') {
door[++doors] = Door(i,j);
num[i][j] = doors;
}
else if(src[i][j] == '.') {
person[++persons] = Empty(i,j);
num[i][j] = persons;
}
}
}
memset(dis,0x3f,sizeof(dis));
for(int i = 1;i <= doors; ++i)
BFS(i);
int l = 0,r = 400,ans = -1;
while(l <= r) {
int mid = (l + r) >> 1;
MakeGraph(mid);
int max_flow = 0;
while(BFS())
max_flow += Dinic(S,INF);
if(max_flow == persons)
ans = mid,r = mid - 1;
else l = mid + 1;
}
if(ans == -1) puts("impossible");
else cout << ans << endl;
return 0;
}
inline void BFS(int p)
{
static queue q;
while(!q.empty()) q.pop();
memset(v,false,sizeof(v));
q.push(Status(door[p].x,door[p].y,0));
while(!q.empty()) {
Status now = q.front(); q.pop();
v[now.x][now.y] = true;
for(int i = 1;i <= 4; ++i) {
int fx = now.x + dx[i];
int fy = now.y + dy[i];
if(v[fx][fy] || !fx || !fy || fx > m || fy > n) continue;
if(src[fx][fy] == '.') {
dis[num[fx][fy]][p] = now.length + 1;
q.push(Status(fx,fy,now.length + 1));
}
}
}
}
inline void MakeGraph(int t)
{
Initialize();
for(int i = 1;i <= persons; ++i)
Add(S,i,1),Add(i,S,0);
for(int i = persons + 1;i <= persons + doors; ++i)
Add(i,T,t),Add(T,i,0);
for(int i = 1;i <= persons; ++i)
for(int j = 1;j <= doors; ++j)
if(dis[i][j] <= t)
Add(i,j + persons,1),Add(j + persons,i,0);
}
inline void Initialize()
{
total = 1;
memset(head,0,sizeof(head));
}
inline void Add(int x,int y,int f)
{
_next[++total] = head[x];
aim[total] = y;
flow[total] = f;
head[x] = total;
}
bool BFS()
{
static queue q;
while(!q.empty()) q.pop();
memset(deep,0,sizeof(deep));
deep[S] = 1;
q.push(S);
while(!q.empty()) {
int x = q.front(); q.pop();
for(int i = head[x];i;i = _next[i])
if(flow[i] && !deep[aim[i]]) {
deep[aim[i]] = deep[x] + 1;
q.push(aim[i]);
if(aim[i] == T) return true;
}
}
return false;
}
int Dinic(int x,int f)
{
if(x == T) return f;
int temp = f;
for(int i = head[x];i;i = _next[i])
if(flow[i] && temp && deep[aim[i]] == deep[x] + 1) {
int away = Dinic(aim[i],min(flow[i],temp));
flow[i] -= away;
flow[i^1] += away;
temp -= away;
}
if(temp == f) deep[x] = 0;
return f - temp;
}