题意:传送门
题解:直接二分答案 mid,也就是所有人安全撤离所需时间, 通过最大流来判断逃生时间为 mid 时,所有人能否安全撤离,能则
缩小边界:
将源点 S 向每个空地连一条容量为 1 的边,表示每个空地初始时有一个人;
因为每一秒钟只能有一个人移动到门的位置,我们要将每个门拆成 mid 个点,分别表示时刻为第 1 ~ mid 秒的门,并向汇点 T 连一条容量为 1 的边;
为了简化问题,在二分答案前我们先 BFS 求出每块空地到每个门所需时间,然后将每块空地与对应所需时间的门连边,容量为1;
那么如果有一些人(人数大于等于1)进入任意一个时刻的门,那么这个时刻的这扇门对应的点必定有 1 的流量流入汇点,但可能会有多个人到达同一个门所需的时间相同,所以我们要让剩下的人等到下一秒再让其中一个人移动到门的位置,所以对于时刻为第 1 ~ mid - 1 秒的门,我们都要向时刻为下一秒的门连一条容量为无穷大的边(因为同一时刻到达门的人可能有任意多,且 mid >= 正确答案时,所有人所代表的流量都将流入汇点 T,所以这里就不多考虑人数了);
判断如此建图的最大流是否等于总人数(总的空地数),如果一直无法相等则说明所有人无法全部安全撤出,输出“impossible”。
最后附上一组样例:
4 5
XXDXX
XX.XX
X...X
XXDXX
附上代码(vector版):
#include
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=20+5;
const int maxt=5e4+5;
const int dx[]={-1,1,0,0},dy[]={0,0,-1,1};
int n,m,E,R,GG[maxn][maxn],dis[100][maxn][maxn],src,des;
char c[maxn][maxn];
bool vis[maxn][maxn];
int q[maxt][2];
const int INF=0x3f3f3f3f;
const int MAX_V=50050;
struct edge{
int to,cap,rev;
edge(int _to,int _cap,int _rev):to(_to),cap(_cap),rev(_rev){}
};
vectorG[MAX_V];
int level[MAX_V];
int iter[MAX_V];
void add_edge(int from,int to,int cap)
{
G[from].push_back(edge(to,cap,G[to].size()));
G[to].push_back(edge(from,0,G[from].size()-1));
}
void bfs(int s)
{
memset(level,-1,sizeof(level));
queueque;
level[s]=0;
que.push(s);
while(!que.empty()){
int v=que.front();que.pop();
for(int i=0;i0&&level[e.to]<0){
level[e.to]=level[v]+1;
que.push(e.to);
}
}
}
}
int dfs(int v,int t,int f)
{
if(v==t){
return f;
}
for(int &i=iter[v];i0&&level[v]0){
e.cap-=d;
G[e.to][e.rev].cap+=d;
return d;
}
}
}
return 0;
}
int max_flow(int s,int t)
{
int flow=0;
for(;;){
bfs(s);
if(level[t]<0){
return flow;
}
memset(iter,0,sizeof(iter));
int f;
while((f=dfs(s,t,INF))>0){
flow+=f;
}
}
return flow;
}
void BFS(int k,int x,int y)
{
memset(vis,false,sizeof(vis));
int s=0,t=1;
vis[x][y]=true;dis[k][x][y]=0;vis[x][y]=true;
q[s][0]=x;q[s][1]=y;
while(sn||ty<1||ty>m||vis[tx][ty]||c[tx][ty]!='.')continue;
dis[k][tx][ty]=dis[k][q[s][0]][q[s][1]]+1;
q[t][0]=tx;q[t][1]=ty;t++;vis[tx][ty]=true;
}
s++;
}
}
inline bool judge(int mi)
{
src=0;des=R+E*mi+1;
for(int i=0;i<=des;i++)G[i].clear();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(c[i][j]=='.')add_edge(src,GG[i][j],1);
}
}
for(int k=1;k<=E;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(c[i][j]=='.'&&dis[k][i][j]<=mi)add_edge(GG[i][j],(k-1)*mi+R+dis[k][i][j],1);
}
}
}
for(int i=1;i<=E;i++){
for(int j=1;j<=mi;j++){
int tmp=(i-1)*mi+R;add_edge(tmp+j,des,1);
if(j!=mi)add_edge(tmp+j,tmp+j+1,inf);
}
}
return max_flow(src,des)==R;
}
int main()
{
memset(dis,inf,sizeof(dis));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%s",c[i]+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(c[i][j]=='D')BFS(++E,i,j);
else if(c[i][j]=='.')GG[i][j]=++R;
}
}
int l=0,r=1000;
while(l+1>1;
if(judge(mid))r=mid;
else l=mid;
}
if(r==1000)printf("impossible\n");
else printf("%d\n",r);
return 0;
}
还有一个不用vector的dinic版:
#include
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=20+5;
const int maxt=5e4+5;
const int dx[]={-1,1,0,0},dy[]={0,0,-1,1};
int n,m,E,R,GG[maxn][maxn],dis[100][maxn][maxn],src,des;
char c[maxn][maxn];
bool vis[maxn][maxn];
int q[maxt][2];
const int INF=0x3f3f3f3f;
const int MAX_V=50050;
int level[MAX_V];
int iter[MAX_V];
struct edge{int v,w,next;}e[1000000];
int head[50050],tot=1;
void add_edge(int u,int v,int w)
{
e[++tot].v=v;e[tot].w=w;e[tot].next=head[u];head[u]=tot;
e[++tot].v=u;e[tot].w=0;e[tot].next=head[v];head[v]=tot;
}
void bfs(int s)
{
for(int i=src;i<=des;i++)iter[i]=head[i],level[i]=-1;
queueque;
level[s]=0;
que.push(s);
while(!que.empty()){
int v=que.front();que.pop();
for(int i=head[v];i;i=e[i].next){
if(e[i].w>0&&level[e[i].v]<0){
level[e[i].v]=level[v]+1;
que.push(e[i].v);
}
}
}
}
int dfs(int v,int t,int f)
{
if(v==t)return f;
for(int &i=iter[v];i;i=e[i].next){
if(e[i].w>0&&level[v]0){
flow+=f;
}
}
return flow;
}
void BFS(int k,int x,int y)
{
memset(vis,false,sizeof(vis));
int s=0,t=1;
vis[x][y]=true;dis[k][x][y]=0;vis[x][y]=true;
q[s][0]=x;q[s][1]=y;
while(sn||ty<1||ty>m||vis[tx][ty]||c[tx][ty]!='.')continue;
dis[k][tx][ty]=dis[k][q[s][0]][q[s][1]]+1;
q[t][0]=tx;q[t][1]=ty;t++;vis[tx][ty]=true;
}
s++;
}
}
inline bool judge(int mi)
{
src=0;des=R+E*mi+1;
memset(head,0,sizeof(head));tot=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(c[i][j]=='.')add_edge(src,GG[i][j],1);
}
}
for(int k=1;k<=E;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(c[i][j]=='.'&&dis[k][i][j]<=mi)add_edge(GG[i][j],(k-1)*mi+R+dis[k][i][j],1);
}
}
}
for(int i=1;i<=E;i++){
for(int j=1;j<=mi;j++){
int tmp=(i-1)*mi+R;add_edge(tmp+j,des,1);
if(j!=mi)add_edge(tmp+j,tmp+j+1,inf);
}
}
return max_flow(src,des)==R;
}
int main()
{
memset(dis,inf,sizeof(dis));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%s",c[i]+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(c[i][j]=='D')BFS(++E,i,j);
else if(c[i][j]=='.')GG[i][j]=++R;
}
}
int l=0,r=1000;
while(l+1>1;
if(judge(mid))r=mid;
else l=mid;
}
if(r==1000)printf("impossible\n");
else printf("%d\n",r);
return 0;
}