zoukankan      html  css  js  c++  java
  • [BZOJ1189][HNOI2007]紧急疏散evacuate

    BZOJ
    Luogu
    以后不放题面了自己看去

    sol

    显然时间是二分的对吧。
    我们二分一个时间,假设为(mid),那么就要把每扇门拆成(mid)个点,各自向汇点连容量为1的边,表示每一扇门在一个单位时间里可以让一个人逃出。
    (BFS)预处理出每个人到每扇门的距离,然后如果这个人在(mid)时间内可以到达这扇门就向这扇门对应的时间点连一条容量为1的边。
    源点向每个人连容量为1的边,然后二分判断最大流是否等于总人数。
    但是!
    如果同一时间有多个人到达了同一扇门,然后其中一个人发挥谦让精神让另一个人先走了,自己在门这里等了一个单位时间才走的,那我们怎么处理呢?
    很简单。从每扇门对应时间(t)的点向(t+1)的点连一条(inf)的边,就可以解决这种问题了。

    code

    细节。。。还好吧
    一些需要注意的点在代码中已经用注释标出

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N = 40;
    const int inf = 1e9;
    int n,m,P[N][N],dis[N<<2][N][N],door,people;
    char g[N][N];
    struct node{int x,y;};
    int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
    queue<int>Q;
    queue<node>QQ;
    void BFS(int k,int p,int q)//第k扇门,它的位置是(p,q)
    {
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			dis[k][i][j]=inf;
    	dis[k][p][q]=0;QQ.push((node){p,q});
    	while (!QQ.empty())
    	{
    		int x=QQ.front().x,y=QQ.front().y;QQ.pop();
    		for (int d=0;d<4;d++)
    		{
    			int i=x+dx[d],j=y+dy[d];
    			if (i<1||i>n||j<1||j>m||g[i][j]!='.') continue;//这里如果写成" g[i][j]=='X' "的话在BZOJ上会WA(但是洛谷可以AC)
    			if (dis[k][i][j]>dis[k][x][y]+1)
    				dis[k][i][j]=dis[k][x][y]+1,QQ.push((node){i,j});
    		}
    	}
    }
    struct edge{int to,next,w;}a[N*N*N*N];
    int S,T,head[N*N*N],cnt,dep[N*N*N],cur[N*N*N];
    void link(int u,int v,int w)
    {
        a[++cnt]=(edge){v,head[u],w};
        head[u]=cnt;
        a[++cnt]=(edge){u,head[v],0};
        head[v]=cnt;
    }
    bool bfs()
    {
        memset(dep,0,sizeof(dep));
        dep[S]=1;Q.push(S);
        while (!Q.empty())
        {
            int u=Q.front();Q.pop();
            for (int e=head[u];e;e=a[e].next)
                if (a[e].w&&!dep[a[e].to])
                    dep[a[e].to]=dep[u]+1,Q.push(a[e].to);
        }
        return dep[T];
    }
    int dfs(int u,int flow)
    {
        if (u==T)
            return flow;
        for (int &e=cur[u];e;e=a[e].next)
            if (a[e].w&&dep[a[e].to]==dep[u]+1)
            {
                int temp=dfs(a[e].to,min(flow,a[e].w));
                if (temp) {a[e].w-=temp;a[e^1].w+=temp;return temp;}
            }
        return 0;
    }
    int Dinic()
    {
        int res=0;
        while (bfs())
        {
            for (int i=T;i;i--) cur[i]=head[i];
            while (int temp=dfs(S,inf)) res+=temp;
        }
        return res;
    }
    int check(int mid)
    {
    	S=door*mid+people+1;T=S+1;
    	memset(head,0,sizeof(head));cnt=1;
    	for (int k=1;k<=door;k++)
    		for (int t=1;t<=mid;t++)
    		{
    			link((k-1)*mid+t,T,1);
    			if (t<mid) link((k-1)*mid+t,(k-1)*mid+t+1,inf);
    		}
    	for (int i=1;i<=people;i++)
    		link(S,door*mid+i,1);
    	for (int k=1;k<=door;k++)
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=m;j++)
    				if (g[i][j]=='.'&&dis[k][i][j]<=mid)//这里一定要写" g[i][j]=='.' ",不然就会把自己这扇门的那个位置也算进去(就这样洛谷上还跑90分?)
    					link(door*mid+P[i][j],(k-1)*mid+dis[k][i][j],1);
    	return Dinic();
    }
    int main()
    {
    	scanf("%d %d",&n,&m);
    	for (int i=1;i<=n;i++)
    		scanf("%s",g[i]+1);
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			if (g[i][j]=='D')
    				BFS(++door,i,j);
    			else if (g[i][j]=='.')
    				P[i][j]=++people;
    	int l=0,r=people+1;
    	while (l<r)
    	{
    		int mid=l+r>>1;
    		if (check(mid)==people) r=mid;
    		else l=mid+1;
    	}
    	if (l==people+1) puts("impossible");
    	else printf("%d
    ",l);
    	return 0;
    }
    
  • 相关阅读:
    Python-Pandas库-DataFrame处理excel/csv表格
    Python-Pandas库-数据结构Series用法总结
    Python-yaml文件处理
    Python-全局配置文件(conf.ini)的读取与写入
    Python-面向对象经典习题
    Python-异常处理
    浅谈postman和jmeter的用法与区别
    性能测试——常用指标的认识
    性能测试——监控工具Grafana的介绍与使用
    ios自动化测试之Java + testng +maven + appium 框架及脚本编写和运行
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8194711.html
Copyright © 2011-2022 走看看