【链接】 我是链接,点我呀:)
【题意】
【题解】
二分+网络流先处理出所有的人到所有的门的最短路dis(x,y)
二分所用的时间mid
则把所有的门都分成mid个。
表示1..mid这些时间这个门可以通过一个人。
然后建立一个超级源点S
S和所有的人各连一条边,边权为1
然后如果人x能到达门y的话
那么从x连mid-dis[x,y]+1条边分别至门的第dis[x,y]个点,第dix[x,y]+1个点....第mid个点(每个点各一条,刚好mid-dis[x][y]+1条。
表示这些时间段这个人都能到达这个点。
然后所有的门都向超级汇点连一条边。
这样可以保证,每个门,每个时刻只有一个人经过
每次跑个最大流
看看是不是满流就好。
(即最大流等于人的个数
是的话mid尝试减小一点
【代码】
#include <bits/stdc++.h>
using namespace std;
const int N = 20;
const int NN = 400;
const int NNN = 160000;
const int INF = 0x3f3f3f3f;
const int dx[4] = {0,0,1,-1};
const int dy[4] = {1,-1,0,0};
struct abc{
int from,en,cost,nex;
};
int n,m,cnt = 1,what[N+10][N+10],now = 0;
int g[NN+10][NN+10],dis[N+10][N+10],dis1[NNN+NN+10],fir[NNN+NN+10],mi[NNN+NN+10],pre[NNN+NN+10];
char s[N+10][N+10];
bool inq[NNN+10];
vector<abc> edge;
queue<pair<int,int> > dl;
queue<int> dl2;
void add_edge(int x,int y,int cost){
abc temp;
temp.from = x,temp.en = y,temp.cost = cost,temp.nex = fir[x];
edge.push_back(temp);
int tot = edge.size()-1;
fir[x] = tot;
}
void bfs(int cur,int x,int y){
memset(dis,INF,sizeof dis);
dis[x][y] = 0;
dl.push(make_pair(x,y));
while (!dl.empty()){
pair<int,int> temp = dl.front();
int xx = temp.first,yy = temp.second;
dl.pop();
for (int i = 0;i < 4;i++){
int tx = xx+dx[i],ty = yy+dy[i];
if (tx>=1 && tx<=n && ty>=1 && ty<=m){
if (s[tx][ty]=='X' || s[tx][ty]=='D') continue;
if (dis[tx][ty]>dis[xx][yy]+1){
dis[tx][ty] = dis[xx][yy]+1;
dl.push(make_pair(tx,ty));
g[what[tx][ty]][cur] = dis[tx][ty];
}
}
}
}
}
bool ok(int t){
memset(fir,255,sizeof fir);edge.clear();
for (int i = 2;i <= cnt;i++) {
add_edge(1,i,1);
add_edge(i,1,0);
}
int cur = cnt,tnow = 0;
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
if (s[i][j]=='D'){
tnow++;
int pp = cur;
for (int k = 1;k <= t;k++) cur++;
for (int k = 2;k <= cnt;k++)
if (g[k][tnow]<INF){
for (int l = pp+g[k][tnow];l <= cur;l++) {
add_edge(k,l,1);
add_edge(l,k,0);
}
}
}
cur++;
for (int i = cnt+1;i <= cur-1;i++) {
add_edge(i,cur,1);
add_edge(cur,i,0);
}
int flow = 0;
while (1){
int s = 1,t = cur;
dis1[s] = 0,inq[s] = 1;
dl2.push(s);
memset(pre,255,sizeof pre);
while (!dl2.empty()){
int x = dl2.front();
dl2.pop();
for (int i = fir[x];i!=-1;i = edge[i].nex){
int y = edge[i].en;
if (edge[i].cost>0 && pre[y]==-1){
pre[y] = i;
dl2.push(y);
}
}
}
if (pre[t]==-1) break;
int now = t,temp1 = INF;
while (now != s){
int temp = pre[now];
temp1 = min(temp1,edge[temp].cost);
now = edge[temp].from;
}
now = t;
while (now!=s){
int temp = pre[now];
edge[temp].cost-=temp1;
edge[temp^1].cost+=temp1;
now = edge[temp].from;
}
flow+=now;
}
if (flow==cnt-1) return true;
else return false;
}
int main(){
//freopen("D:\rush.txt","r",stdin);
scanf("%d%d",&n,&m);
for (int i = 1;i <= n;i++) scanf("%s",s[i]+1);
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
if (s[i][j]=='.'){
cnt++;
what[i][j] = cnt;
}
memset(g,INF,sizeof g);
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
if (s[i][j]=='D'){
bfs(++now,i,j);
}
int l = 1,r = n*m,temp = -1;
while (l <= r){
int m = (l+r)>>1;
if (ok(m)){
temp = m;
r = m - 1;
}else l = m + 1;
}
if (temp==-1){
printf("impossible
");
}else{
printf("%d
",temp);
}
return 0;
}