One-Way Roads(建模跑最大流)

                                         One-Way Roads

                                                                     时间限制: 1 Sec  内存限制: 64 MB
                                                                                提交: 200  解决: 34
                                                                     [提交] [状态] [讨论版] [命题人:admin]

题目描述

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

题意: 一个国家有N个城市,m个双向道路,现在要把所有双向道路改成单项道路,问改成单向道路之后所有城市中入度最大的至少是多少。

题解:最大流建图:
每条边转换成一个节点,代表一条边的该节点有两条边指向该边连接 的两城市,容量为1。所有城市连向超级汇点,容量为x,表示二分出来的入度,通过限制入度的方式限制最大流。超级源点连向每一条代表边的节点,容量为1。跑出来的最大流即在该最大入度下能正常走到的边数。
建图大概形态如下:

在这里插入图片描述

这样一开始每条边的容量1,保证了每条边只能被走一次,然后连到城市的容量可能有多条路径,这样使得流量增加,通过了一个城市的入度即使如此。接着城市连向超级汇点会被度数x限制,因此当度数较低时,一些被迫,不得不承接那么多道路入度的城市,将会因为被限制了度数而不能跑出满流,满流的形态即m条道路都能走过,就表示是所有道路都被改成了单行道,当不满流时表示二分出来的最大度数太少了,连基本的满流都做不到,需要提高二分出来的度数。
而当能跑出满流时,就面临了一些道路的走向选择,是指向两个城市中的哪一个,这样的抉择将决定着城市的最大入度,最小化最大入度即从这里入手。我们通过在满流的条件下不断压缩最大度数,来实现单向边的方向选择,尽量对承受太多入度的城市分摊掉度数。

每次二分都要将图恢复成跑最大流之前的图。(但是因为调用函数就不需要)

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define mset(a,i) memset(a,i,sizeof(a))
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAX=5080;
int n,m,k;
struct edge
{
    ll t,cap,flow,next;    //cap容量,flow流量
}e[MAX*10];
int head[MAX],cur[MAX],cnt; //cur优化dfs中的head
struct node
{
    int from,to;
}a[MAX];
void add(int u,int v,int cap)   //u->v容量为cap
{

    e[cnt].t=v;
    e[cnt].cap=cap;
    e[cnt].flow=0;
    e[cnt].next=head[u];
    //e[cnt]=node{v,cap,0,head[u]};
    head[u]=cnt++;
    //e[cnt]=node{u,0,0,head[v]};
    e[cnt].t=u;//容量为0的反向边
    e[cnt].cap=0;
    e[cnt].flow=0;
    e[cnt].next=head[v];
    head[v]=cnt++;
}
int d[MAX];    //bfs深度
bool bfs(int s,int t)   //O(n+m)
{
    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;i=e[i].next)
        {
            int v=e[i].t;
            if(d[v]==0&&e[i].cap-e[i].flow>0)
            {
                d[v]=d[u]+1;
                q.push(v);
            }
        }
    }
    return d[t]>0;     //存在增广路
}
ll dfs(int s,int t,ll minedge)
{
    if(s==t)return minedge;
    ll flow=0;    //从当前s点流出的流量
    for(int &i=cur[s];~i;i=e[i].next)
    {
        int v=e[i].t;
        if(d[v]==d[s]+1&&e[i].cap-e[i].flow>0)   //层次关系&&有剩余流量
        {
            ll temp=dfs(v,t,min(minedge-flow,e[i].cap-e[i].flow));
            e[i].flow+=temp;    //流量增加
            e[i^1].flow-=temp;    //反向边流量减少
            flow+=temp;    //flow已分配的流量
            if(flow==minedge)return flow;  //已达到祖先的最大流,无法再大,剪枝
        }
    }
    if(flow==0)d[s]=0;   //此点已无流,标记掉
    return flow;
}
ll dinic(int s,int t)   //一定要建立反向边cap=0
{
    ll maxflow=0;
    while(bfs(s,t))   //有增广路
    {
        memcpy(cur,head,sizeof(head));   //重要的优化
        maxflow+=dfs(s,t,INF);
    }
    return maxflow;
}
int init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
}
bool judge(int x)
{

    int st=n+m+1;
    int ed=st+1;
    for(int i=1;i<=m;i++)
    {
        add(st,i,1);
        add(i,m+a[i].from,1);
        add(i,m+a[i].to,1);
    }
    for(int i=1;i<=n;i++) add(m+i,ed,x);
    return dinic(st,ed)==m;
}
int main()
{
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<=m;i++) scanf("%d%d",&a[i].from,&a[i].to);
    int l=0,r=n,ans=0;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(judge(mid)) r=mid-1,ans=mid;
        else l=mid+1;
    }
    printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_41021816/article/details/82984813