https://darkbzoj.cf/problem/2095

bzoj 相同的题挂了,这个oj可以写。

题目就是要我们找一条欧拉回路(每个桥经过一次就好,不管方向),使得这条回路上权值最大的尽量小
二分答案是显然的,关键是如何check

每次二分一个mid,大于mid的边都不选,那么就有一些方向不能走了,原图就是一个混合图,问题就转化成了一个混合图判定欧拉回路问题(如果有一条边两个方向都不能走,那肯定不存在欧拉回路)
对于那些单向边,直接统计度数就可以。对于两个方向都可以走的边,先随便定一个方向,假设是u->v,统计度数,并且在网络图里加一条边u->v,流量为1。
最后遍历所有的点u,如果入度与出度之差为奇数,显然无解(某一次进去就出不来了,或者出来就进不去了)
如果u出度大于入度,那么加边S->u,流量(out-in)/2   就是要调整多少条边 
如果u入度大于出度,那么加边u->T,流量(in-out)/2
最后满流才有欧拉回路

这样做的正确性:
双向边是随意定向的,因此这个定向可能是错的,才会导致一些点出度和入度不相等(如果欧拉回路本来存在的话)。如果把一条原本是v->u的边定成了u->v,那么u就多了出度,v就少了入度。要修正这个错误,就需要让u->v边反向,达到u出度-1,v入度+1的目的。也就是S->u->v->T这条流量的含义。当然反过来建也是可以的:S->v->u->T
如果最后不能满流,说明有一些点的入度没办法等于出度,那肯定不存在欧拉回路

AC代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e3+,mod=1e9+,inf=0x3f3f3f3f;
typedef long long ll;
struct edge
{
int from,to,c,f;
edge(int u,int v,int c,int f):from(u),to(v),c(c),f(f) {}
};
int n,m;
vector<edge> edges;
vector<int> g[maxn];
int d[maxn];//从起点到i的距离
int cur[maxn];//当前弧下标
struct bian
{
int a,b,c,d;
}qiao[maxn];
int in[maxn],out[maxn];
void init()
{
for(int i=; i<=n+; i++) g[i].clear(); //要把源点汇点算进去!!
edges.clear();
}
void addedge(int from,int to,int c) //加边 支持重边
{
edges.push_back(edge(from,to,c,));
edges.push_back(edge(to,from,,));
int siz=edges.size();
g[from].push_back(siz-);
g[to].push_back(siz-);
}
int bfs(int s,int t) //构造一次层次图
{
memset(d,-,sizeof(d));
queue<int> q;
q.push(s);
d[s]=;
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=;i<g[x].size();i++)
{
edge &e=edges[g[x][i]];
if(d[e.to]<&&e.f<e.c) //d[e.to]=-1表示没访问过
{
d[e.to]=d[x]+;
q.push(e.to);
}
}
}
return d[t];
}
int dfs(int x,int a,int t) // a表示x点能接收的量
{
if(x==t||a==)return a;
int flow=,f;//flow总的增量 f一条增广路的增量
for(int &i=cur[x];i<g[x].size();i++)//cur[i] &引用修改其值 从上次考虑的弧
{
edge &e=edges[g[x][i]];
if(d[x]+==d[e.to]&&(f=dfs(e.to,min(a,e.c-e.f),t))>) //按照层次图增广 满足容量限制
{
e.f+=f;
edges[g[x][i]^].f-=f; //修改流量
flow+=f;
a-=f;
if(a==) break;
}
}
return flow;
}
int maxflow(int s,int t)
{
int flow=;
while(bfs(s,t)!=-) //等于-1代表构造层次图失败 结束
{
memset(cur,,sizeof(cur));
flow+=dfs(s,inf,t);
}
return flow;
}
int check(int mid)
{
memset(in,,sizeof(in));
memset(out,,sizeof(out));
init();
for(int i=;i<m;i++)
{
if(qiao[i].c<=mid&&qiao[i].d<=mid)
{
addedge(qiao[i].a,qiao[i].b,);
in[qiao[i].b]++,out[qiao[i].a]++;
}
else if(qiao[i].c<=mid)
in[qiao[i].b]++,out[qiao[i].a]++;
else if(qiao[i].d<=mid)
in[qiao[i].a]++,out[qiao[i].b]++;
else
return ;
}
int sum=;
for(int i=;i<=n;i++)
{
int temp=out[i]-in[i];
if(temp&)
return ;
if(temp>)
addedge(n+,i,temp/),sum+=temp/;
if(temp<)
addedge(i,n+,-temp/);
}
return sum==maxflow(n+,n+);
}
int main()
{
scanf("%d%d",&n,&m);
int u,v,c,f;
for(int i=;i<m;i++)
{
scanf("%d%d%d%d",&u,&v,&c,&f);
qiao[i]={u,v,c,f};
}
int l=,r=,ans=-;
while(l<=r)
{
int mid=(l+r)/;
if(check(mid))
{
ans=mid;
r=mid-;
}
else
l=mid+;
}
if(ans==-)
printf("NIE\n");
else
printf("%d\n",ans);
}

[Poi2010]Bridges 最大流+二分答案 判定混合图欧拉回路的更多相关文章

  1. POJ1637 Sightseeing tour(判定混合图欧拉回路)

    有向连通图存在欧拉回路的充要条件是所有点入度=出度. 首先随便给定所有无向边一个方向(不妨直接是u->v方向),记录所有点的度(记:度=入度-出度). 这时如果有点的度不等于0,那么就不存在欧拉 ...

  2. bzoj 2095: [Poi2010]Bridges [混合图欧拉回路]

    2095: [Poi2010]Bridges 二分答案,混合图欧拉路判定 一开始想了一个上下界网络流模型,然后发现不用上下界网络流也可以 对于无向边,强制从\(u \rightarrow v\),计算 ...

  3. BZOJ2095 POI2010 Bridges 【二分+混合图欧拉回路】

    BZOJ2095 POI2010 Bridges Description YYD为了减肥,他来到了瘦海,这是一个巨大的海,海中有n个小岛,小岛之间有m座桥连接,两个小岛之间不会有两座桥,并且从一个小岛 ...

  4. 【BZOJ-2095】Bridge 最大流 + 混合图欧拉回路 + 二分

    2095: [Poi2010]Bridges Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 604  Solved: 218[Submit][Stat ...

  5. POJ 1637 - Sightseeing tour - [最大流解决混合图欧拉回路]

    嗯,这是我上一篇文章说的那本宝典的第二题,我只想说,真TM是本宝典……做的我又痛苦又激动……(我感觉ACM的日常尽在这张表情中了) 题目链接:http://poj.org/problem?id=163 ...

  6. POJ 1637 Sightseeing tour(混合图欧拉回路+最大流)

    http://poj.org/problem?id=1637 题意:给出n个点和m条边,这些边有些是单向边,有些是双向边,判断是否能构成欧拉回路. 思路: 构成有向图欧拉回路的要求是入度=出度,无向图 ...

  7. POJ 1637 Sightseeing tour ★混合图欧拉回路

    [题目大意]混合图欧拉回路(1 <= N <= 200, 1 <= M <= 1000) [建模方法] 把该图的无向边随便定向,计算每个点的入度和出度.如果有某个点出入度之差为 ...

  8. POJ 1637 混合图欧拉回路

    先来复习一下混合图欧拉回路:给定一张含有单向边和双向边的图,使得每一点的入度出度相同. 首先对于有向边来说,它能贡献的入度出度是确定的,我们不予考虑.对于无向图,它可以通过改变方向来改变两端点的出入度 ...

  9. poj1637Sightseeing tour(混合图欧拉回路)

    题目请戳这里 题目大意:求混合图欧拉回路. 题目分析:最大流.竟然用网络流求混合图的欧拉回路,涨姿势了啊啊.. 其实仔细一想也是那么回事.欧拉回路是遍历所有边一次又回到起点的回路.双向图只要每个点度数 ...

随机推荐

  1. ubuntu frp 自编译。本文不能按顺序来 请自己理解

    go run:go run 编译并直接运行程序,它会产生一个临时文件(但不会生成 .exe 文件),直接在命令行输出程序执行结果,方便用户调试. go build:go build 用于测试编译包,主 ...

  2. 浅谈js的sort()方法

    如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码(字符串Unicode码点)的顺序进行排序.要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以 ...

  3. 二. python函数与模块

    第四章.内置函数与装饰器详解 1.内置函数补充1 注:红色圆圈:必会:  紫红色方框:熟练:   绿色:了解 callable() 判断函数是否可以被调用执行 def f1(): pass f1() ...

  4. ios之UIWebView(1)

    UIWebView可以让你创建一个网页浏览器,类似safari,而不是在程序中启动safsri哦.是不是觉得很棒呢?废话少说,切入正题. 一.创建UIWebView [java] view plain ...

  5. CSS实现跳动的桃心

    又来刷题--CSS动画实现跳动的桃心,从哪里跌倒就从哪里爬起来,哈哈哈~ 分析:首先,得画出一个桃心,然后再用动画效果让它跳起来(关于动画,实在是弱项啊~~~,得补补了). 第一步:画桃心,思路是一个 ...

  6. LeetCode 最长连续递增序列

    给定一个未经排序的整数数组,找到最长且连续的的递增序列. 示例 1: 输入: [1,3,5,4,7] 输出: 3 解释: 最长连续递增序列是 [1,3,5], 长度为3. 尽管 [1,3,5,7] 也 ...

  7. Luogu P1080国王游戏(贪心)

    国王游戏 题目链接:国王游戏 ps:题目数据说明了要写高精度. 这个题的答案是\(a.l * a.r < b.l * b.r\)按照这个进行排序 题解中大部分只是如何证明排序是: \(a.l * ...

  8. 【线段树 集合hash】bzoj4373: 算术天才⑨与等差数列

    hash大法好(@ARZhu):大数相乘及时取模真的是件麻烦事情 Description 算术天才⑨非常喜欢和等差数列玩耍.有一天,他给了你一个长度为n的序列,其中第i个数为a[i].他想考考你,每次 ...

  9. (34)zabbix Queue队列

    概述 queue(队列)显示监控项等待刷新的时间,可以看到每种agent类型刷新时间,通过queue可以更好的体现出监控的一个指标.正常情况下,是一片绿色. 如果出现过多红色,那么需要留意一下.我们也 ...

  10. 文件操作-cp

    Linux cp命令 也是我们在实际使用中非常常用的一个命令,主要用来复制文件.文件夹等.今天就来给大家介绍下 cp命令 的使用. 转载自 https://www.linuxdaxue.com/lin ...