[bzoj1189]紧急疏散

Posted pywbktda

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj1189]紧急疏散相关的知识,希望对你有一定的参考价值。

二分答案+判定,对于一个答案,源点向每一个点连一条流量为1的边,每一扇门向汇点连一条流量为时间的边,每一个人向每一个在答案时间内能走到的门连一条流量为1的边,跑最大流并判断流量是否等于人数。

然而自从bzoj新增数据后就跑不过了,原因是不能保证有一组最优撤离方案使得在最后一个时刻以前(最后一个时刻可能人不够),每一扇门每一个时刻都有人出去(具体数据见bzoj讨论板)。

可以对门拆为时间个点,每一个点向它到某扇门的最早时间以后每一个时刻的门连一条流量为1的边,每一个门现在只有1的流量,再跑网络流即可(只要开40000个点和5000000条边即可,当然最坏的点数/边数要比这个大)。

技术图片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 50005
  4 #define id i*m+j+1
  5 struct ji
  6     int nex,to,len;
  7 edge[N*100];
  8 queue<int>q;
  9 int E,T,n,m,pe,head[N],work[N],d[N],vis[405][405],bh[405][41];
 10 char s[31][31];
 11 void add(int x,int y,int z)
 12     edge[E].nex=head[x];
 13     edge[E].to=y;
 14     edge[E].len=z;
 15     head[x]=E++;
 16     if (E&1)add(y,x,0);
 17 
 18 bool bfs(int k)
 19     memset(d,-1,sizeof(d));
 20     q.push(k);
 21     d[k]=0;
 22     while (!q.empty())
 23         k=q.front();
 24         q.pop();
 25         for(int i=head[k];i!=-1;i=edge[i].nex)
 26             if ((edge[i].len)&&(d[edge[i].to]<0))
 27                 d[edge[i].to]=d[k]+1;
 28                 q.push(edge[i].to);
 29             
 30     
 31     return d[T]>=0;
 32 
 33 int dfs(int k,int s)
 34     if (k==T)return s;
 35     for(int &i=work[k];i!=-1;i=edge[i].nex)
 36         if ((edge[i].len)&&(d[edge[i].to]==d[k]+1))
 37             int p=dfs(edge[i].to,min(s,edge[i].len));
 38             if (p)
 39                 edge[i].len-=p;
 40                 edge[i^1].len+=p;
 41                 return p;
 42             
 43         
 44     return 0;
 45 
 46 int dinic()
 47     int k,ans=0;
 48     while (bfs(0))
 49         memcpy(work,head,sizeof(head));
 50         while (k=dfs(0,0x3f3f3f3f))ans+=k;
 51     
 52     return ans;
 53 
 54 bool pd(int mid)
 55     memset(head,-1,sizeof(head));
 56     E=0;
 57     for(int i=0;i<n;i++)
 58         for(int j=0;j<m;j++)
 59             if (s[i][j]==.)
 60                 add(0,id,1);
 61                 for(int k=0;k<n*m;k++)
 62                     if (s[k/m][k%m]==D)
 63                         for(int l=vis[id][k];l<=mid;l++)add(id,bh[k+1][l],1);
 64             
 65             if (s[i][j]==D)
 66                 for(int k=1;k<=mid;k++)add(bh[id][k],T,1);
 67         
 68     return dinic()==pe;
 69 
 70 int main()
 71     scanf("%d%d",&n,&m);
 72     memset(head,-1,sizeof(head));
 73     for(int i=0;i<n;i++)scanf("%s",s[i]);
 74     for(int i=0;i<n;i++)
 75         for(int j=0;j<m;j++)
 76             if (s[i][j]!=X)
 77                 if ((j)&&(s[i][j-1]!=X)&&((s[i][j-1]!=D)||(s[i][j]!=D)))add(id,id-1,1);
 78                 if ((j<m-1)&&(s[i][j+1]!=X)&&((s[i][j+1]!=D)||(s[i][j]!=D)))add(id,id+1,1);
 79                 if ((i)&&(s[i-1][j]!=X)&&((s[i-1][j]!=D)||(s[i][j]!=D)))add(id,id-m,1);
 80                 if ((i<n-1)&&(s[i+1][j]!=X)&&((s[i+1][j]!=D)||(s[i][j]!=D)))add(id,id+m,1);
 81             
 82     for(int i=0;i<n;i++)
 83         for(int j=0;j<m;j++)
 84             if (s[i][j]==.)
 85                 bfs(id);
 86                 pe++;
 87                 for(int k=1;k<=n*m;k++)
 88                     if (d[k]==-1)vis[id][k-1]=10000;
 89                     else vis[id][k-1]=d[k];
 90             
 91     T=n*m+1;
 92     for(int i=0;i<n;i++)
 93         for(int j=0;j<m;j++)
 94             if (s[i][j]==D)
 95                 for(int k=1;k<=pe;k++)bh[id][k]=T++;
 96     int l=0,r=pe+1;
 97     while (l<r)
 98         int mid=(l+r>>1);
 99         if (pd(mid))r=mid;
100         else l=mid+1;
101     
102     if (l>pe)printf("impossible");
103     else printf("%d",l);
104 
View Code

 

以上是关于[bzoj1189]紧急疏散的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 1189[HNOI2007]紧急疏散evacuate

[bzoj1189] [HNOI2007]紧急疏散evacuate

BZOJ1189[HNOI2007]紧急疏散evacuate 动态加边网络流

[bzoj1189]紧急疏散

BZOJ 1189 [HNOI2007]紧急疏散evacuate

BZOJ 1189 HNOI2007 紧急疏散evacuate