[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

 

posted @ 2019-07-28 10:45  PYWBKTDA  阅读(177)  评论(0编辑  收藏  举报