bzoj 1189 二分+BFS+网络最大流

来源:互联网 发布:绿色建筑计算软件 编辑:程序博客网 时间:2024/06/05 16:52

~~~~~~~~~~~~~~~~~

题目大意:紧急疏散。有一张地图,‘.’表示人,‘D’表示门,人需要走曼哈顿距离的单位时间才1能到达门。一个门一个时刻只能通过一个人。求多长时间能疏散完毕。

首先第一感觉肯定要BFS,要算出每个人到每个门的用时

其次,优化题目意思,t时间,有num个人可以到达door[i],但是最多仅有t个人可以穿过这个门(每秒钟只可通过一个人),这就清晰的出现一个网络最大流的轮廓。

二分T时间(0-400),在T时间内,S向每个人建立流量为1的边,如果一个人在规定时间t内可以到达某一门,建立一条边,流量为1,最后门与汇点建立流量为T的边。二分跑出答案即可!

#include <map>#include <set>#include <queue>#include <stack>#include <math.h>#include <vector>#include <cstdio>#include <string>#include<string.h>#include <fstream>#include <iostream>#include <algorithm>using namespace std;#define exp 1e-8#define INF 100000000#define ll long long#define exp 1e-8#define INF 100000000#define ll long long#define set(a,b) memset(a,b,sizeof(a));#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)#define for0(a,b) for(int a=0;a<=b;a++)//0---(b-1)#define For(i,a,b) for(int i=a;i<=b;i++)#define each(a,u) for(int a=head[u];a!=-1;a=e[a].next)void bug(string st="bug"){cout<<st<<endl;}template<typename __ll>inline void READ(__ll &m){    __ll x=0,f=1;char ch=getchar();    while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    m=x*f;}template<typename __ll>inline void read(__ll &m){READ(m);}template<typename __ll>inline void read(__ll &m,__ll &a){READ(m);READ(a);}template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}struct DOOR{    int x,y;}door[1000],CUR,tmp;int doorcnt=1;int cost[30][30][100];int dx[]={1,-1,0,0};int dy[]={0,0,1,-1};int g[30][30];  //墙是0  人是1  可移动的地方   们是2int n,m;#define INF 999999999;const int maxn=2000000; //边的数量,应该比正常边的数量多两倍const int MAXN=10000;//节点数int s,t,tot;int cur[MAXN];//当前弧优化int pre[MAXN];//先祖int level[MAXN];//高度int gap[MAXN];//gap优化struct EDGE{int to,cost,next;}edge[maxn];int head[maxn],cnt;inline void addedge(int a,int b,int c){edge[cnt].to=b;edge[cnt].cost=c;edge[cnt].next=head[a];head[a]=cnt++;edge[cnt].to=a;edge[cnt].cost=0;edge[cnt].next=head[b];head[b]=cnt++;}#define  getid(i,j) (i-1)*n+jvoid build_graph(int n,int m,int mid) //节点数(1->n),边数{s=0,t=n*m+1,tot=n*m+2,cnt=0;//cnt=0为了更好的异或memset(head,-1,sizeof(head));for1(i,n) for1(j,m)        if(g[i][j]==1)        {            addedge(s,getid(i,j),1);            for1(idx,doorcnt-1)                if(cost[i][j][idx]<=mid)                    addedge(getid(i,j),getid(door[idx].x,door[idx].y),1);        }    for1(idx,doorcnt-1)        addedge(getid(door[idx].x,door[idx].y),t,mid);}int sap()  //无需改动{memset(pre,-1,sizeof(pre));memset(gap,0,sizeof(gap));memset(level,0,sizeof(level));        gap[0]=tot;int u=s,ans=0,inf=INF;for(int i=0; i<tot; i++)//初始化当前弧为第一条弧cur[i]=head[i];while(level[s]<tot){bool flag=0;for(int &i=cur[u];i!=-1;i=edge[i].next) //读取边,并更新当前弧{int v=edge[i].to;if(edge[i].cost>0&&level[u]==level[v]+1){flag=1;if(edge[i].cost<inf)inf=edge[i].cost;pre[v]=u;u=v;if(u==t){while(u!=s) //结束后u==s{u=pre[u];edge[cur[u]].cost-=inf;edge[cur[u]^1].cost+=inf;//异或是找与其配对的边}ans+=inf;inf=INF;}break;}}if(!flag){if(--gap[level[u]]==0)//gap优化break;int minn=tot;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;if(edge[i].cost>0&&level[v]<minn){minn=level[v];cur[u]=i;//更新当前弧,让其从度最小的线段开始}}level[u]=minn+1;gap[minn+1]++;if(u!=s)u=pre[u];}}return ans;}void bfs(int idx)  //第几个门{    for1(i,n) for1(j,m)        cost[i][j][idx]=INF;    cost[door[idx].x][door[idx].y][idx]=0;//初始化    bool vis[30][30];    set(vis,0);    CUR=door[idx];    queue<DOOR>que;    que.push(CUR);    vis[CUR.x][CUR.y]=1;    while(!que.empty())    {        CUR=que.front();        que.pop();        vis[CUR.x][CUR.y]=0;        for0(i,4)        {            int x=CUR.x+dx[i];            int y=CUR.y+dy[i];            if(x>=1&&x<=n&&y>=1&&y<=m&&g[x][y]==1)            {                if(cost[x][y][idx]>cost[CUR.x][CUR.y][idx]+1)                {                    cost[x][y][idx]=cost[CUR.x][CUR.y][idx]+1;                    if(!vis[x][y])                    {                        vis[x][y]=1;                        tmp.x=x,tmp.y=y;                        que.push(tmp);                    }                }            }        }    }}int main(){    read(n,m);    int sum=0,ans=-1;    for1(i,n)    {        char ch[30];        scanf("%s",ch+1);        for1(j,m)            if(ch[j]=='X')                g[i][j]=0;            else if(ch[j]=='.')                g[i][j]=1,sum++;            else if(ch[j]=='D')            {                door[doorcnt].x=i,door[doorcnt++].y=j;                g[i][j]=2;            }    }    for1(i,doorcnt-1)        bfs(i);  //求最短距离    int l=0,r=410;    while(l<r)    {        int mid=(l+r>>1);        build_graph(n,m,mid);  //新建图        if(sap()==sum) r=mid;  //对比答案        else l=mid+1;    }    if(410==r)        cout<<"impossible\n";    else    cout<<r<<endl;    return 0;}


0 0
原创粉丝点击