【BZOJ 1189】 [HNOI2007]紧急疏散evacuate

添加数据的人的ID就在原题目下面 大家知道该怎么做了吧

还有一点 读入是要小心 新增的数据格式好像有问题 用%s 读入整行吧

题解

没加数据时都会做
新加数据后 我们应把每个D bfs一遍 求出每个. 到他的距离
把每个D分成很多个 每个代表一个时间 相邻两个时间连边 表示可以=待
按照.D的距离分别连边到对应的D

最后 二分时 把Dt连边 权值为1 连到mid秒时停止

额 差不多了 说具体就不好了 自己实现吧 具体过程看个人习惯 不要怕开变量!!!
下面是 原汁原味的带注释代码 我自己都不想读 每个变量代表什么意思 我都要看一会......

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define MAXN 1000000
#define INF 100000000
using namespace std;
int xx[5]={0,0,0,1,-1};
int yy[5]={0,1,-1,0,0};
int g[MAXN],num[MAXN],nnext[MAXN],flow[MAXN],tot=2;
void Add(int x,int y,int f){/*cout<<x<<' '<<y<<' '<<f<<endl;*/nnext[tot]=g[x];g[x]=tot;num[tot]=y;flow[tot]=f;tot++;}
int d[MAXN],team[MAXN],head,tail;
int id[21][21],idt[401][10000],cnt=0;
int a[22][22];
int n,m,s,t;
int tt[MAXN],ntt=0,nans=0;
int tmpflow[MAXN],tmpg[MAXN];
int dis[401][401];
int now;
bool bfs()
{
    head=tail=0;memset(d,0,sizeof(d));
    d[s]=1;team[++tail]=s;
    while(head<tail)
    {
        int x=team[++head]; //cout<<x<<' '<<d[x]<<endl;
        for(int i=g[x];i;i=nnext[i])
            if(d[num[i]]==0&&flow[i]!=0)
                d[num[i]]=d[x]+1,team[++tail]=num[i];
    }
//  cout<<d[t]<<endl;
    if(d[t]==0) return false;
    return true;
}
int dfs(int x,int mmin)
{
    if(x==t) return mmin;
    int tmp,f=0;
    for(int i=g[x];i;i=nnext[i])
        if(d[num[i]]==d[x]+1&&flow[i]!=0&&(tmp=dfs(num[i],min(mmin,flow[i]))))
        {
            flow[i]-=tmp;
            flow[i^1]+=tmp;
            f+=tmp,mmin-=tmp;
            if(mmin==0) return f;
        }
    return f;
}
bool F(int mid)
{
    for(int i=now;i<=tot;i++) nnext[tot]=0;
    for(int i=0;i<=now;i++) flow[i]=tmpflow[i];
    for(int i=0;i<=cnt;i++) g[i]=tmpg[i]; g[t]=tmpg[t]; //cout<<g[t]<<endl;
    tot=now;//cout<<cnt<<endl;
    for(int i=1;i<=ntt;i++)
        for(int j=1;j<=mid;j++)
        {
            int tmp=tt[i];
            Add(idt[tmp][j],t,1);
            Add(t,idt[tmp][j],0);
        }
//  cout<<"fs";
    int ans=0;
    while(bfs()) ans+=dfs(s,INF);
//  cout<<mid<<' '<<ans<<endl;
    if(ans==nans) return true;
    return false;
}
int q[MAXN][2];
bool b[21][21];
void spfa(int x,int y)
{
    head=tail=0;int thiss =id[x][y];
    q[++tail][0]=x,q[tail][1]=y;dis[thiss][thiss]=1;
    while(head<tail)
    {
        x=q[++head][0],y=q[head][1];b[x][y]=false; int nowd=dis[thiss][id[x][y]];
        for(int i=1;i<=4;i++)
        {
            int tx=x+xx[i],ty=y+yy[i];
            if(tx<1||tx>n||ty<1||ty>m) continue;
            int idd=id[tx][ty];
            if(a[tx][ty]==1&&dis[thiss][idd]==0||dis[thiss][idd]>nowd)
            {
                dis[thiss][idd]=nowd+1;
                if(!b[tx][ty]) 
                {
                    b[tx][ty]=true;
                    q[++tail][0]=tx;
                    q[tail][1]=ty;
                }
            }   
        }
    }
    idt[thiss][1]=++cnt;
    for(int i=2;i<=1000;i++)
        idt[thiss][i]=++cnt,Add(cnt-1,cnt,INF),Add(cnt,cnt-1,0);    
    
    dis[thiss][thiss]=0;
    for(int i=1;i<=n*m;i++)
    if(dis[thiss][i]!=0)
    {
        dis[thiss][i]--;
        int tmp=dis[thiss][i]; 
    //  cout<<i<<' '<<idt[thiss][tmp]<<endl;
        Add(i,idt[thiss][tmp],1);
        Add(idt[thiss][tmp],i,0);
    }
}
char ss[200];
int main()
{
//  freopen("a.in","r",stdin);
//  freopen("a.out","w",stdout);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
    /*  char c=getchar();
        for(int j=1;j<=m;j++)
        {
            id[i][j]=++cnt;

            c=getchar();
            if(c=='X') a[i][j]=0;
            if(c=='.') a[i][j]=1,nans++;
            if(c=='D') a[i][j]=2;
        }*/
        scanf("%s",ss+1);
        for(int j=1;j<=m;j++)
        {
            id[i][j]=++cnt;

            if(ss[j]=='X') a[i][j]=0;
            if(ss[j]=='.') a[i][j]=1,nans++;
            if(ss[j]=='D') a[i][j]=2;
        }
    }
    s=0;t=1000000-1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(a[i][j]==2)
                spfa(i,j),tt[++ntt]=id[i][j];
            else if(a[i][j]==1)
                Add(s,id[i][j],1),
                Add(id[i][j],s,0);
    now=tot;
    for(int i=0;i<=now;i++) tmpflow[i]=flow[i];
    for(int i=0;i<=cnt;i++) tmpg[i]=g[i]; tmpg[t]=g[t];
    
//  cout<<cnt<<endl;
    int L=0,R=1000;
    while(L<R)
    {
        int mid=(L+R)/2;
        if(F(mid)) R=mid;
        else L=mid+1;
    }
    if(L==1000)  cout<<"impossible";
    else cout<<L<<endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值