【网络流】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\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;
}

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

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

    POJ图论分类[转] 一个很不错的图论分类,非常感谢原版的作者!!!在这里分享给大家,爱好图论的ACMer不寂寞了... (很抱歉没有找到此题集整理的原创作者,感谢知情的朋友给个原创链接) POJ:h ...

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

    Barricade Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...

  3. HDU 5889 (最短路+网络流)

    Barricade Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...

  4. HDU 3416 Marriage Match IV (最短路径,网络流,最大流)

    HDU 3416 Marriage Match IV (最短路径,网络流,最大流) Description Do not sincere non-interference. Like that sho ...

  5. SGU 206. Roads

    206. Roads time limit per test: 0.5 sec. memory limit per test: 65536 KB input: standard output: sta ...

  6. HDU 5352——MZL's City——————【二分图多重匹配、拆点||网络流||费用流】

    MZL's City Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  7. CF546E Soldier and Traveling(网络流,最大流)

    CF546E Soldier and Traveling 题目描述 In the country there are \(n\) cities and \(m\) bidirectional road ...

  8. 【题解】Paid Roads [SP3953] [Poj3411]

    [题解]Paid Roads [SP3953] [Poj3411] 传送门:\(\text{Paid}\) \(\text{Roads}\) \(\text{[SP3953]}\) \(\text{[ ...

  9. Codeforces 546 E:士兵的旅行 最大网络流

    E. Soldier and Traveling time limit per test 1 second memory limit per test 256 megabytes input stan ...

随机推荐

  1. C# 直接使用sql语句对数据库操作 (cmd.ExecuteNonQuery)

    只介绍读和删 不管使用什么方法来对数据库进行操作都绕不开和数据库的连接问题,所以咱们先在App.config中添加连接字段 <connectionStrings> <add name ...

  2. 在swift调用OC的第三方库

    https://www.jianshu.com/p/4799ac1d7dce 2017.06.02 23:55* 字数 275 阅读 1619评论 0喜欢 3 环境:xcode 8.3.2 系统: M ...

  3. C/C++学习笔记_gdb调试

    1.前提条件:可执行文件包含调试信息 gcc -g 2.gdb 文件名 ---启动gdb调试 3.查看代码的命令 当前文件: list 行号(函数名) 指定文件: list 文件名:行号(函数名)4. ...

  4. c 循环左移

    char b[11] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}; const int iShift = 4; for (int j = ...

  5. 深入理解 Java —— GC 机制

    1. 基础知识 1.1 什么是垃圾回收? 程序的运行必然需要申请内存资源,无效的对象资源如果不及时处理就会一直占有内存资源,最终将导致内存溢出,所以对内存资源的管理非常重要. 垃圾回收就是对这些无效资 ...

  6. Python的 5 种高级用法,效率提升没毛病!

    任何编程语言的高级特征通常都是通过大量的使用经验才发现的.比如你在编写一个复杂的项目,并在 stackoverflow 上寻找某个问题的答案.然后你突然发现了一个非常优雅的解决方案,它使用了你从不知道 ...

  7. plt画log图

    import matplotlib.pyplot as plt import math import numpy as np x = np.arange(-0.85,0.95,0.05) #获得函数结 ...

  8. Java线程——线程之间的数据共享

      在 Java 传统线程机制中的共享数据方式,大致可以简单分两种情况: ➢ 多个线程行为一致,共同操作一个数据源.也就是每个线程执行的代码相同,可以使用同一个 Runnable 对象,这个 Runn ...

  9. 吴裕雄--天生自然MySQL学习笔记:MySQL 索引

    MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度. 打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是 ...

  10. 吴裕雄--天生自然 JAVASCRIPT开发学习: HTML DOM - 改变CSS

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...