zoukankan      html  css  js  c++  java
  • EOJ Monthly 2020.3 A.迷宫 (二分+最大流)

    题目链接

    https://acm.ecnu.edu.cn/contest/255/problem/A/

    题意

    给出有向图,有(m)个人在顶点(S),每天晚上你可以控制他们呆在原地不动或选择移动到下一个顶点(从一个顶点到相邻顶点恰好需要花费一个晚上时间),当然,你可以控制每一个青年有不一样的选择。每条边都有一个容量(C),代表着在同一个晚上最多(C) 个人可以穿过该边。
    现在要求你在最少的时间内帮助所有人到达迷宫的出口(T)
    保证给出的图,至少存在一条路径能从(S)(T)

    思路

    官方题解:
    考虑二分答案。
    我们现在要判断,所有人能否在(mid)天内走出去。
    因为道路限制了每天通过的流量,我们不妨拆点,分层建图,把每一个点拆成 (标号,天数) 在相邻节点相邻的天数之间连边,然后跑最大流就好了。
    比如样例的图我们这样去建:
    Alt text

    #include<bits/stdc++.h>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    const int N = 5100;
    const int M = 2e6+10;
    struct node{int u,v,w;}a[N];
    struct edge{int to,cap,next;}e[M];
    int head[N],tot;
    int d[N],cur[N];
    int k,n,m,S,T,s,t;
    void add(int u,int v,int w)
    {
        e[++tot].to=v,e[tot].cap=w;
        e[tot].next=head[u],head[u]=tot;
    }
    bool Bfs()
    {
    	memset(d,0,sizeof(d));
    	queue<int>q;
    	q.push(s);
    	d[s]=1;
    	while(!q.empty())
    	{
    		int u=q.front();
    		q.pop();
    		for(int i=head[u];i!=-1;i=e[i].next)
    		{
    			int v=e[i].to;
    			if(!d[v]&&e[i].cap)
    			{
    				d[v]=d[u]+1;
    				q.push(v);
    			}
    		}
    	}
    	return d[t];
    }
    int Dfs(int u,int flow)
    {
    	if(u==t||!flow) return flow;
    	int used=0;
    	for(int i=cur[u];i!=-1;i=e[i].next)
    	{
    		cur[u]=i;
    		int v=e[i].to;
    		if(d[v]==d[u]+1&&e[i].cap)
    		{
    			int fl=Dfs(v,min(flow,e[i].cap));
    			if(fl)
    			{
    				used+=fl;
    				flow-=fl;
    				e[i].cap-=fl;
    				e[i^1].cap+=fl;
    				if(!flow) break;
    			}
    		}
    	}
    	return used;
    }
    int Dinic()
    {
    	int sum=0;
    	while(Bfs())
    	{
    		memcpy(cur,head,sizeof(head));
    		sum+=Dfs(s,inf);
    	}
    	return sum;
    }
    bool judge(int x)
    {
        tot=-1;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=m;i++)
        {
            int u=a[i].u,v=a[i].v,w=a[i].w;
            for(int j=0;j<x;j++)
                add(u+j*n,v+(j+1)*n,w),add(v+(j+1)*n,u+j*n,0);
        }
        for(int i=1;i<=n;i++)
            for(int j=0;j<x;j++)
                add(i+j*n,i+(j+1)*n,inf),add(i+(j+1)*n,i+j*n,0);
        s=S,t=T+x*n;
        int tmp=Dinic();
        if(tmp>=k)return true;
        else return false;
    }
    int main()
    {
        scanf("%d%d%d%d%d",&k,&n,&m,&S,&T);
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
        int l=1,r=100,ans;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(judge(mid))r=mid-1,ans=mid;
            else l=mid+1;
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    【算法】哈希表法四部曲
    【算法】位运算技巧
    【算法】分治法四步走
    【算法】分支界限三步走
    【Java】位操作符
    【Java】String字符串格式化
    阿里一面,给了几条SQL,问需要执行几次树搜索操作?
    c++随机数问题研究
    Google单元测试框架gtest之官方sample笔记4--事件监控之内存泄漏测试
    Google单元测试框架gtest之官方sample笔记3--值参数化测试
  • 原文地址:https://www.cnblogs.com/HooYing/p/12541758.html
Copyright © 2011-2022 走看看