这个题是非常暴力的匹配问题。
首先最好想的思路是给每个人分门的决策,
每个人到每个门的距离直接暴力最短路即可
但不能算出一个门被多个人经过的情况
所以就有了暴力的想法,再给每个人、对每一个门分配一个时间。
这样的话时间的范围就必须确定,不然就是动态借边的网络流
由于时间满足二分的条件,所以二分+网络流检验即可
码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
#define inf 1000000009
int tot,ans,l,r,s,t,n,d[3000000],m,i,j,k,hou[3000000],v[3000000],zhong[3000000],yuan[3000000],xia[3000000];
char tu[40][40];
bool vis[3000000];
vector<int>D,dian,jl[3000000];
queue<int>q;
void jian(int a,int b,int c)
{
++tot;hou[tot]=yuan[a];yuan[a]=tot;v[tot]=c;zhong[tot]=b;
}
void jia(int a,int b,int c)
{
jian(a,b,c);
jian(b,a,0);
}
void spfa(int o)
{int i;
memset(d,0x7f,sizeof(d));
q.push(o);
d[o]=0;
while(!q.empty())
{
int st=q.front();
q.pop();
vis[st]=0;
for(i=yuan[st];i!=-1;i=hou[i])
{
int nd=zhong[i];
if(d[nd]>d[st]+1)
{
d[nd]=d[st]+1;
if(vis[nd]==0)
{
vis[nd]=1;
q.push(nd);
}
}
}
}
}
bool bfs()
{
int i;
memset(d,0x7f,sizeof(d));
for(i=1;i<=t;i++)
xia[i]=yuan[i];
q.push(s);
d[s]=0;
while(!q.empty())
{
int st=q.front();
q.pop();
for(i=xia[st];i!=-1;i=hou[i])
{
int nd=zhong[i];
if(!v[i]||d[nd]<inf)continue;
d[nd]=d[st]+1;
q.push(nd);
}
}
return d[t]<inf;
}
int dfs(int o,int t,int limit)
{
if(o==t||limit==0)return limit;
int i,flow=0,f;
for(i=xia[o];i!=-1;i=hou[i])
{
xia[o]=i;
int nd=zhong[i];
if(d[nd]==d[o]+1&&(f=dfs(nd,t,min(limit,v[i]))))
{
flow+=f;
limit-=f;
v[i]-=f;
v[i^1]+=f;
if(limit==0)break;
}
}
return flow;
}
int dinic()
{
int daan=0;
while(bfs())
{
daan+=dfs(s,t,inf);
}
return daan;
}
int main()
{
memset(yuan,-1,sizeof(yuan));
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
scanf("%c",&tu[i][j]);
while(tu[i][j]!='X'&&tu[i][j]!='.'&&tu[i][j]!='D')scanf("%c",&tu[i][j]);
if(tu[i][j]=='D')D.push_back((i-1)*m+j);
else if(tu[i][j]=='.')dian.push_back((i-1)*m+j);
}
for(i=2;i<n;i++)
for(j=2;j<m;j++)
{
if(tu[i][j]=='X')continue;
if(tu[i-1][j]!='X')jian((i-1)*m+j,(i-2)*m+j,1);
if(tu[i+1][j]!='X')jian((i-1)*m+j,(i)*m+j,1);
if(tu[i][j+1]!='X')jian((i-1)*m+j,(i-1)*m+j+1,1);
if(tu[i][j-1]!='X')jian((i-1)*m+j,(i-1)*m+j-1,1);
}
r=400;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
if(tu[i][j]=='X')continue;
spfa((i-1)*m+j);
int lin=999;
for(k=0;k<D.size();k++)
{
int xy=D[k];
jl[(i-1)*m+j].push_back(d[xy]);
lin=min(lin,d[xy]);
}
// cout<<(i-1)*m+j<<" : "<<jl[(i-1)*m+j].size()<<endl;
r=max(lin,r);
}
if(r>400)
{
printf("impossible");
return 0;
}
s=n*m+400*400+1;
t=s+1;
l=0;
while(l<r)
{
int mid=(l+r)>>1;
tot=-1;//cout<<mid;
memset(yuan,-1,sizeof(yuan));
for(i=0;i<dian.size();i++)
{
int st=dian[i];
jia(s,st,1);
for(j=0;j<D.size();j++)
{ //cout<<st<<" "<<jl[st].size()<<endl;
int nd=jl[st][j];
for(k=nd;k<=mid;k++)
{
jia(st,n*m+(400*j)+k,1);
}
}
}
for(i=0;i<D.size();i++)
for(j=1;j<=mid;j++)jia(n*m+400*i+j,t,1);
if(dinic()==dian.size())
{
ans=mid;
r=mid;
}else l=mid+1;
}
printf("%d",ans);
}