【网络流】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 traf?c. To alleviate the problem, the politicians of Via came up with the magni?cent 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-i?cation”.
The mayors do not want too many one-way roads to lead to their cities because this can cause traf?c jam within the city: they demand that the smallest integer d be found such that there is a ‘one-way-i?cation’ 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\n",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\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/smallocean/p/9749078.html

时间: 2024-08-29 21:52:48

【网络流】One-Way Roads的相关文章

图论常用算法之一 POJ图论题集【转载】

POJ图论分类[转] 一个很不错的图论分类,非常感谢原版的作者!!!在这里分享给大家,爱好图论的ACMer不寂寞了... (很抱歉没有找到此题集整理的原创作者,感谢知情的朋友给个原创链接) POJ:http://poj.org/ 1062* 昂贵的聘礼 枚举等级限制+dijkstra 1087* A Plug for UNIX 2分匹配 1094 Sorting It All Out floyd 或 拓扑 1112* Team Them Up! 2分图染色+DP 1125 Stockbroker

[转] 一些图论、网络流入门题总结、汇总

最短路问题此类问题类型不多,变形较少 POJ 2449 Remmarguts' Date(中等)http://acm.pku.edu.cn/JudgeOnline/problem?id=2449题意:经典问题:K短路解法:dijkstra+A*(rec),方法很多相关:http://acm.pku.edu.cn/JudgeOnline/showcontest?contest_id=1144该题亦放在搜索推荐题中 POJ 3013 - Big Christmas Tree(基础)http://ac

【转】一些图论、网络流入门题总结、汇总

最短路问题 此类问题类型不多,变形较少 POJ 2449 Remmarguts' Date(中等) http://acm.pku.edu.cn/JudgeOnline/problem?id=2449 题意:经典问题:K短路 解法:dijkstra+A*(rec),方法很多 相关:http://acm.pku.edu.cn/JudgeOnline/showcontest?contest_id=1144 该题亦放在搜索推荐题中 POJ 3013 - Big Christmas Tree(基础) ht

HDU 5889 (最短路+网络流)

Barricade Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1117    Accepted Submission(s): 340 Problem Description The empire is under attack again. The general of empire is planning to defend hi

[转载] 一些图论、网络流入门题总结、汇总

转载 最短路问题此类问题类型不多,变形较少 POJ 2449 Remmarguts' Date(中等)http://acm.pku.edu.cn/JudgeOnline/problem?id=2449题意:经典问题:K短路解法:dijkstra+A*(rec),方法很多相关:http://acm.pku.edu.cn/JudgeOnline/showcontest?contest_id=1144该题亦放在搜索推荐题中 POJ 3013 - Big Christmas Tree(基础)http:/

ZOJ3792_Romantic Value(网络流/最小割=最大流/找割边)

解题报告 题目传送门 题意: 给出一个无向图,以及起点与终点.要删除一些边使得起点与终点不连通,在删掉边的权值之和最小的情况下要求删除的边数尽量少. 求出一个比值:剩余边数权值和/删除的边数. 思路: 明显的让起点终点达不到就是一个最小割,用最大流可以求出. 但是求割边边数就不会了,没做过最小割的求割边问题. 割边一定是残留网络中零流的边,但零流不一定是割边. 飞神的想法很奇特.链接传送 可以把残留网络的零流的边设成容量为1,其他设成无穷,再求一次最大流.最后流量一定等于割边边数 另外: 还有一

一系列网络流题目-2016.10.18

稍微修改了一下最大流的算法,昨天整理代码的有错误.本来想把算法封装成一个模板类,结果运行时间直接从2秒变成了超时,那道题总时间是15秒,单点限制5秒. HDU3416:Marriage Match IVTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3581 Accepted Submission(s): 1056 Problem Descri

MZL&#39;s City(网络流)

MZL's City Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 496    Accepted Submission(s): 164 Problem Description MZL is an active girl who has her own country. Her big country has N cities num

HDU5889 Barricade(最短路)(网络流)

Barricade Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 604    Accepted Submission(s): 172 Problem Description The empire is under attack again. The general of empire is planning to defend his