BZOJ 1189: [HNOI2007]紧急疏散evacuate
作者:互联网
远古时期的HNOI,这题感觉内存开小了吧,虽然数据也不是满的。如果是满的数据,128MB根本不够啊。
20 20
.DDDDDDDDDDDDDDDDDD.
D..........D.......D
D.......D..........D
D..................D
D.....D...D........D
D........D....D....D
D.............D....D
D....D...D.........D
D..................D
D..................D
D....D......D......D
D..................D
D...........D......D
D.....D............D
D..................D
D.D..D..D...D......D
D..................D
D....D...D..D......D
D...D..D..D...D....D
.DDDDDDDDDDDDDDDDDD.
不考虑数据和内存的问题的话,预处理距离后,二分枚举答案,通过跑最大流来验证即可。
#include <bits/stdc++.h>
using namespace std;
const int N=21;
const int dx[4]={0,-1,0,1},dy[4]={-1,0,1,0};
int n,m,tot,size1,size2;
int id[N][N],d[N*N][N*N],a[N*N],b[N*N];
bool vis[N][N];
char str[N][N];
struct node{int x,y,z;};
queue<node>q;
inline void init(int x,int y)
{
memset(vis,false,sizeof(vis));
int now=id[x][y];
q.push((node){x,y,0}); vis[x][y]=true; d[now][id[x][y]]=0;
while (q.size())
{
node u=q.front(); q.pop();
for (register int i=0; i<4; ++i)
{
int xx=u.x+dx[i],yy=u.y+dy[i];
if (xx<1 || xx>n || yy<1 || yy>m) continue;
if (str[xx][yy]=='X' || vis[xx][yy]) continue;
vis[xx][yy]=true;
if (str[xx][yy]=='.') q.push((node){xx,yy,u.z+1});
else d[now][id[xx][yy]]=u.z+1;
}
}
//洛谷过后发现BZOJ错了一个点,附上该点数据
//原来,当一个门后面存在另一个门,且这个门是另一个门联通外界的门户时,
//(即另一个门想出去只能通过这个门或其他门,而不能通过'.')
//这个门后面的另一个个门,是不会用到的。
//可以这样证明:如果一个人到达了前面的门不出去,那么他还是要走至少一步才能到达后面的另一个门
//而由于一个门在一时间内只能存在一个人,无论出不出去,所以他后面的人还是只能和原来一样等待
//可能他后面的人从他不出去的这个门出去的同时,他也能从另一个门出去
//但是如果他从另一个门出去的话,最好的结果最多是和他从前一个门直接出去的结果一样优
//所以我们对于那种:“最好结果”只能和前面的门一样优的门,就不去考虑了。
//现在有同学说:即使考虑了也没有关系,反正我们跑的是最大流啊,哪怕是从另一个门出去也能得到最优答案。
//确实是能够得到最优答案,但是这对于我们建图就有一些影响了
//观察下面的这组数据:
/*
5 4
XDXX
DXXX
D..X
X..X
XXXX
*/
//如果我们要算(2,1)的'D'与'.'的距离的话,就显得比较麻烦了。
//一开始我觉得,可以用这种写法
/*if (str[xx][yy]=='.') q.push((node){xx,yy,u.z+1});
else
{
d[now][id[xx][yy]]=u.z+1;
q.push((node){xx,yy,u.z+2});
}*/
//但是这种写法又会被类似以下的样例叉掉
/*
5 4
XXXX
D.XX
D..X
X..X
XXXX
*/
//而如果一定要把没用的点放进去的话,跑bfs就要改为跑dij了,多加一支log
// 有没有觉得很愚蠢啊,为了一个可以省略的东西多加一支log
//所以那种方法我就不写了。
}
const int M=2e5+5,MM=1e6+5;
int s,t;
int dep[M];
int cnt,hh,head[M];
struct edge{int next,to,w;}e[MM];
inline void add(int u,int v,int w)
{
cnt++;
e[cnt].next=head[u];
e[cnt].to=v;
e[cnt].w=w;
head[u]=cnt;
}
queue<int>q1;
inline bool bfs()
{
memset(dep,-1,sizeof(dep));
dep[s]=0; q1.push(s);
while (q1.size())
{
int u=q1.front(); q1.pop();
for (register int i=head[u]; i; i=e[i].next)
if (e[i].w && dep[e[i].to]==-1)
{
dep[e[i].to]=dep[u]+1;
q1.push(e[i].to);
}
}
if (dep[t]==-1) return false;
else return true;
}
int dfs(int u,int flow)
{
if (u==t) return flow;
int remain=flow;
for (register int i=head[u]; i; i=e[i].next)
if (e[i].w && dep[u]+1==dep[e[i].to])
{
int k=dfs(e[i].to,min(remain,e[i].w));
if (!k) {dep[e[i].to]=-1; continue;}
remain-=k; e[i].w-=k; e[i^1].w+=k;
if (!remain) break;
}
return flow-remain;
}
inline int dinic()
{
int ans=0;
while (bfs()) ans+=dfs(s,2e9);
return ans;
}
inline bool jay(int mid)
{
cnt=1; memset(head,0,sizeof(head));
s=0; t=size1+size2*mid+1;
for (register int i=1; i<=size1; ++i) add(s,i,1),add(i,s,0);
for (register int i=1; i<=size1; ++i)
for (register int j=1; j<=size2; ++j)
for (register int k=d[a[i]][b[j]]; k<=mid; ++k) add(i,size1+(j-1)*mid+k,1),add(size1+(j-1)*mid+k,i,0);
for (register int i=size1+1; i<=size1+size2*mid; ++i) add(i,t,1),add(t,i,0);
hh=max(hh,cnt);
if (dinic()>=size1) return true;
else return false;
}
int main(){
// freopen("1189.in","r",stdin);
// freopen("1189.out","w",stdout);
memset(d,60,sizeof(d));
//本来没有写这个初始化,结果发现洛谷提交70分,原来是因为有一些'D'被封闭掉,根本达到不了
scanf("%d%d",&n,&m);
for (register int i=1; i<=n; ++i) scanf("%s",str[i]+1);
for (register int i=1; i<=n; ++i)
for (register int j=1; j<=m; ++j)
{
id[i][j]=++tot;
if (str[i][j]=='.') a[++size1]=id[i][j];
if (str[i][j]=='D') b[++size2]=id[i][j];
}
for (register int i=1; i<=n; ++i)
for (register int j=1; j<=m; ++j) if (str[i][j]=='.') init(i,j);
int l,r,mid,ans;
l=0; r=n*m; ans=-1;
while (l<=r)
{
mid=l+r>>1;
if (jay(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
if (ans==-1) puts("impossible");
else printf("%d\n",ans);
// printf("%d\n",hh);
return 0;
}
Love_xyh
发布了86 篇原创文章 · 获赞 85 · 访问量 1765
私信
关注
标签:return,..,1189,int,evacuate,yy,dep,xx,HNOI2007 来源: https://blog.csdn.net/Dove_xyh/article/details/104434377