• 【网络流】One-Way Roads


    【网络流】One-Way Roads

    题目描述

    In the country of Via, the cities are connected by roads that can be used in both directions.
    However, this has been the cause of many accidents since the lanes are not separated: The drivers frequently look at their smartphones while driving, causing them to collide with the oncoming traffic. To alleviate the problem, the politicians of Via came up with the magnificent idea to have one-way roads only, i.e., the existing roads are altered such that each can be only used in one of two possible directions. They call this “one-way-ification”.
    The mayors do not want too many one-way roads to lead to their cities because this can cause traffic jam within the city: they demand that the smallest integer d be found such that there is a ‘one-way-ification’ in which for every city, the number of one-way roads leading to it is at most d.

    输入

    The input consists of:
    • one line with an integer n (1 ≤ n ≤ 500), where n is the number of cities labeled from 1 to n;
    • one line with an integer m (0 ≤ m ≤ 2.5 · 103 ), where m is the number of (bi-directional) roads;
    • m lines describing the roads. Each road is described by:
    – one line with two integers a and b (1 ≤ a, b ≤ n, a≠b) indicating a road between cities a and b.
    There is at most one road between two cities.

    输出

    Output the minimum number d.

    样例输入

    2
    1
    1 2

    样例输出

    1

    还没看出来是网络流。题目问:赋予方向,让每个点最大的入度最小。然后每条边方向信号相当于给每个点一个权值,然后一条边只能给一个点一个权值。就想到用网络流。通过满不满流来判断合法性。

    方法一:二分

    二分枚举每个点流向汇点的流量,如果与进来的流量相同,就说明可行,不相同则不可以。每次都要初始化并建边

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <cmath>
    #include <map>
    #include <set>
    #define ll long long
    #define ull unsigned long long
    const int inf=0x3f3f3f3f;
    using namespace std;
    const int maxn=3e3+10;
    const int maxm=2e4+100;
    template<class T>
    void read(T &res)
    {
        res = 0;
        char c = getchar();
        T f = 1;
        while(c < '0' || c > '9')
        {
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9')
        {
            res = res * 10 + c - '0';
            c = getchar();
        }
        res *= f;
    }
    struct Dinic
    {
        struct Edge
        {
            int next,f,to;
        } e[maxm];
        int head[maxn],dep[maxn],tol,ans;
        int cur[maxn];
        int src,sink,n;
        void add(int u,int v,int f)
        {
            tol++;
            e[tol].to=v;
            e[tol].next=head[u];
            e[tol].f=f;
            head[u]=tol;
            tol++;
            e[tol].to=u;
            e[tol].next=head[v];
            e[tol].f=0;
            head[v]=tol;
        }
        bool bfs()
        {
            queue<int>q;
            memset(dep,-1,sizeof(dep));
            q.push(src);
            dep[src]=0;
            while(!q.empty())
            {
                int now=q.front();
                q.pop();
                for(int i=head[now]; i; i=e[i].next)
                {
                    if(dep[e[i].to]==-1&&e[i].f)
                    {
                        dep[e[i].to]=dep[now]+1;
                        if(e[i].to==sink)
                            return true;
                        q.push(e[i].to);
                    }
                }
            }
            return false;
        }
        int dfs(int x,int maxx)
        {
            if(x==sink)
                return maxx;
            for(int& i=cur[x]; i; i=e[i].next)
            {
                if(dep[e[i].to]==dep[x]+1&&e[i].f>0)
                {
                    int flow=dfs(e[i].to,min(maxx,e[i].f));
                    if(flow)
                    {
                        e[i].f-=flow;
                        e[i^1].f+=flow;
                        return flow;
                    }
                }
            }
            return 0;
        }
        int dinic(int s,int t)
        {
            ans=0;
            this->src=s;
            this->sink=t;
            while(bfs())
            {
                for(int i=0; i<=n; ++i)
                    cur[i]=head[i];
                while(int d=dfs(src,inf))
                    ans+=d;
            }
            return ans;
        }
        void init(int n)
        {
            this->n=n;
            memset(head,0,sizeof(head));
            tol=1;
        }
    } G;
    struct node{int u,v;}s[maxm];
    int n,m;
    bool check(int k){
        G.init(n+m+1);
        for(int i=1;i<=m;++i){
            G.add(0,i,1);
            G.add(i,m+s[i].u,1);
            G.add(i,m+s[i].v,1);
        }
        for(int i=1;i<=n;++i){
            G.add(m+i,n+m+1,k);
        }
        int max_flow=G.dinic(0,n+1+m);
        if(max_flow==m){
            return 1;
        }
        else return 0;
    }
    int main()
    {
        read(n);read(m);
        G.init(n+m+1);
        for(int i=1; i<=m; ++i)
        {
            read(s[i].u);
            read(s[i].v);
        }
        int l=0,r=maxm+10;
        int ans,mid;
        while(l<r){
            mid=(l+r)/2;
            if(check(mid)){
                ans=mid;
                r=mid;
            }
            else l=mid+1;
        }
        printf("%d
    ",ans);
        return 0;
    }
    

    方法二:残余网络

    标记流向汇点的正向边的编号。由于它点数比较少,所以可以for循环,每次让正向边流量加一然后跑残余网络,一合法就是正确答案。

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <cmath>
    #include <map>
    #include <set>
    #define ll long long
    #define ull unsigned long long
    const int inf=0x3f3f3f3f;
    using namespace std;
    const int maxn=3e3+10;
    const int maxm=2e4+100;
    struct Dinic
    {
        struct Edge
        {
            int next,f,to;
        } e[maxm];
        int head[maxn],dep[maxn],tol,ans;
        int cur[maxn];
        int src,sink,n;
        void add(int u,int v,int f)
        {
            tol++;
            e[tol].to=v;
            e[tol].next=head[u];
            e[tol].f=f;
            head[u]=tol;
            tol++;
            e[tol].to=u;
            e[tol].next=head[v];
            e[tol].f=0;
            head[v]=tol;
        }
        bool bfs()
        {
            queue<int>q;
            memset(dep,-1,sizeof(dep));
            q.push(src);
            dep[src]=0;
            while(!q.empty())
            {
                int now=q.front();
                q.pop();
                for(int i=head[now]; i; i=e[i].next)
                {
                    if(dep[e[i].to]==-1&&e[i].f)
                    {
                        dep[e[i].to]=dep[now]+1;
                        if(e[i].to==sink)
                            return true;
                        q.push(e[i].to);
                    }
                }
            }
            return false;
        }
        int dfs(int x,int maxx)
        {
            if(x==sink)
                return maxx;
            for(int& i=cur[x]; i; i=e[i].next)
            {
                if(dep[e[i].to]==dep[x]+1&&e[i].f>0)
                {
                    int flow=dfs(e[i].to,min(maxx,e[i].f));
                    if(flow)
                    {
                        e[i].f-=flow;
                        e[i^1].f+=flow;
                        return flow;
                    }
                }
            }
            return 0;
        }
        int dinic(int s,int t)
        {
            ans=0;
            this->src=s;
            this->sink=t;
            while(bfs())
            {
                for(int i=0; i<=n; i++)
                    cur[i]=head[i];
                while(int d=dfs(src,inf))
                    ans+=d;
            }
            return ans;
        }
        void init(int n)
        {
            this->n=n;
            memset(head,0,sizeof(head));
            tol=1;
        }
    } G;
    int num[maxm];
    int main()
    {
        int n,m,u,v;
        scanf("%d%d",&n,&m);
        G.init(n+m+1);
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&u,&v);
            G.add(0,i,1);
            G.add(i,m+u,1);
            G.add(i,m+v,1);
        }
        for(int i=1; i<=n; i++)
        {
            G.add(m+i,n+m+1,0);
            num[i]=G.tol-1;
        }
        int t=0;
        int ans=0;
        while(t<m){
            ans++;
            for(int i=1;i<=n;i++){
                G.e[num[i]].f+=1;
            }
            t+=G.dinic(0,n+m+1);
        }
        printf("%d
    ",ans);
        return 0;
    }
    
    
    不要忘记努力,不要辜负自己 欢迎指正 QQ:1468580561
  • 相关阅读:
    valueof这个万能方法,将string转换为int或者int转换为string都可以
    java的数组index[]方括号内是可以进行算数运算的
    项目工程的包package与文件夹的关系
    导入项目后下载jar包问题理解
    MySQL 5.6.19 二进制安装
    左右 android AES 所述机器的一部分 javax.crypto.BadPaddingException: pad block corrupted
    iOS_词典阵列 按key分组和排序
    Maven真——聚合和继承(于)
    机器学习Matlab打击垃圾邮件的分类————朴素贝叶斯模型
    切点算法模板(Cut-vertex)
  • 原文地址:https://www.cnblogs.com/smallocean/p/9749078.html
Copyright © 2020-2023  润新知