1. 程式人生 > >GCPC2016 One-Way Roads(建模跑最大流)

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

2785: One-Way Roads

時間限制: 1 Sec  記憶體限制: 64 MB
提交: 196  解決: 31
[提交] [狀態] [討論版] [命題人: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

來源/分類

[提交] [狀態]

【題意】

給出無向圖,對於每一條邊,現在把它變成有向。完成後,每個點的入度為d,最大的入度為maxd,求最小的maxd

【分析】

網路流建模。

建立超級源點S匯點T,在原圖中每一條有向邊的中間插入一個附加點j,源點S向所有的j連一條邊,容量為1,然後j向其兩邊的那兩個點分別連邊,容量為1,這樣就滿足了,附加點j僅能選擇一條出路。最後將所有點向T連一條邊,容量為x(未知)。

二分求x。每次二分都要將圖恢復成跑最大流之前的圖。試一下當前列舉的x能否使得模型圖的最大流達到m,達到才是滿足的x

【程式碼】

#include<bits/stdc++.h>
#define read(i) scanf("%d",&i)
using namespace std;
typedef long long ll;
const int MAX=1e5+5;
struct node{
    int t,next;
    int flow;
}edge[MAX<<1];
int head[MAX],cur[MAX],cnt;
void initedge(int n)
{
    memset(head,-1,sizeof(head[0])*++n);cnt=0;
}
void addedge(int u,int v,int cap)
{
    edge[cnt]=node{v,head[u],cap};
    head[u]=cnt++;
    edge[cnt]=node{u,head[v],0};
    head[v]=cnt++;
}

int deep[MAX],temp[MAX];
bool bfs(int s,int t,int ver)
{
    for(int i=0;i<=ver;i++)deep[i]=-1;
    deep[s]=1;
    int front=0,tail=0,*q=temp;
    q[tail++]=s;
    while(front<tail)
    {
        int u=q[front++];
        for(int i=head[u];~i;i=edge[i].next)
        {
            int v=edge[i].t;
            if(deep[v]==-1&&edge[i].flow>0)
            {
                deep[v]=deep[u]+1;
                q[tail++]=v;
            }
        }
    }
    return deep[t]>0;
}
int dfs(int s,int t,int minflow)
{
    if(s==t)return minflow;
    int flow=0;
    for(int &i=cur[s];~i;i=edge[i].next)
    {
        int v=edge[i].t;
        if(deep[s]+1!=deep[v]||edge[i].flow<=0)continue;
        ll temp=dfs(v,t,min(minflow,edge[i].flow));
        edge[i].flow-=temp;
        edge[i^1].flow+=temp;
        flow+=temp;
        if(flow==minflow)return flow;
    }
    if(flow==0)deep[s]=-1;
    return flow;
}
int dinic(int s,int t,int ver)
{
    int flow=0;
    while(bfs(s,t,ver))
    {
        for(int i=0;i<=ver;i++)cur[i]=head[i];
        flow+=dfs(s,t,1e9);
    }
    return flow;
}

int main()
{
    int n,m,u,v;
    read(n); read(m);
    initedge(n);
    for(int i=1;i<=m;i++)
    {
        read(u); read(v);
        addedge(0,i,1);
        addedge(i,u+m,1);
        addedge(i,v+m,1);
    }
    int tag=cnt;
    for(int i=1;i<=n;i++)addedge(i+m,n+m+1,1e9);
    int l=0,r=m,mid;
    while(l<r)
    {
        mid=(l+r)>>1;
        for(int i=0;i<tag;i++)edge[i].flow=(i&1)?0:1;
        for(int i=tag;i<cnt;i++)edge[i].flow=(i&1)?0:mid;

        if(dinic(0,n+m+1,n+m+1)==m)r=mid;
        else l=mid+1;
    }
    printf("%d\n",r);
}