UVA 10735 Euler Circuit (最大流)
题意:求混合图的欧拉路径。
一句话总结:网络流,最主要在于建图,此题是将出度则是和流量联系在了一起,用最大流来调整边的指向。
分析:
这题的困难之处在于无向边只能用一次,相当于一个方向未定的有向边。
首先用并查集判断图的连通性,(直接计数O(1),做1395 Slim Span学到的技巧)。
我们知道有向图的欧拉路径存在的充要条件是最多两个点的入度不等于出度,而且相差为1。这题要求回路,只需要所有点的入度等于出度就行了。
对于无向边,一开始可以随意确定一个方向。这样不能保证所有点的入度等于出度,但是可以想办法调整。
比如说u->v,那么如果改变方向的话,就相当于把一个出度运输给了v。
这让人联想到了网络流,一条无向边就对应着一条容量为1的边,建图的时候就把u在v直接连一条容量为1的边。
那么剩下的就是决定怎么运输?运输多少?我们的目标是调整使得所有的点入度等于出度。
因为每次调整入度和出度的差改变都为偶,那么如果有入度和出度相差为奇数的点,那么一定是不满足条件的。
下面只考虑度数差为偶的点,对于入度大于出度的点,那么这个点需要出度,需要(in[u]-out[u])/2个出度,那么就把它和汇点连一条相应容量的边。
对于出度大的点类似处理。跑网络流,进行调整。根据残流网络,可以得出边的指向。在跑Euler路径就行了。
#include<bits/stdc++.h>
using namespace std; int V,E;
const int maxv = ;
#define PB push_back vector<int> D[maxv]; int in[maxv],out[maxv]; struct Edge
{
int v,cap;
}; vector<Edge> edges;
vector<int> G[maxv];
int S,T;
int vcnt;
void AddEdge(int u,int v,int c)
{
G[u].PB(edges.size());
edges.PB({v,c});
G[v].PB(edges.size());
edges.PB({u,});
} int lv[maxv];
int q[maxv]; bool bfs()
{
memset(lv,,sizeof(int)*(vcnt));
int l = , r = ;
q[r++] = S; lv[S] = ;
while(r>l){
int u = q[l++];
for(int i = ; i < G[u].size(); i++){
Edge &e = edges[G[u][i]];
if(!lv[e.v] && e.cap){
lv[e.v] = lv[u]+;
q[r++] = e.v;
}
}
}
return lv[T];
} int cur[maxv];
int dfs(int u,int a)
{
if(u == T||!a) return a;
int flow = ,f;
for(int &i = cur[u]; i < G[u].size(); i++){
Edge &e = edges[G[u][i]];
if(lv[e.v] == lv[u]+ && (f = dfs(e.v,min(e.cap,a)))){
flow += f;
a -= f;
e.cap -= f;
edges[G[u][i]^].cap+=f;
if(!a) break;
}
}
return flow;
} const int INF = 0x3f3f3f3f;
int MaxFlow()
{
int flow = ;
while(bfs()){
memset(cur,,sizeof(int)*(vcnt));
flow += dfs(S,INF);
}
return flow;
} int build()
{
int del = ;
for(int i = ; i <= V; i++){
int d;
if((in[i]+out[i])&) return -;
if(out[i]<in[i]) {
d = (in[i]-out[i])>>; del+=d; AddEdge(i,T,d);
}else if(in[i]<out[i]){
d = (out[i]-in[i])>>;
AddEdge(S,i,d);
}
}
return del;
} int pa[maxv];
int Find(int x) { return x == pa[x]?x:pa[x]=Find(pa[x]); }
bool vis[maxv];
int cnt; void init()
{
S = ; T = V+; vcnt = T+;
for(int i = ; i <= V; i++) D[i].clear(),in[i]=out[i]=;
edges.clear();
for(int i = ; i <= T; i++) G[i].clear();
for(int i = ; i <= V; i++) pa[i] = i;
memset(vis,,sizeof(bool)*vcnt);
cnt = ;
} bool read()
{
scanf("%d%d",&V,&E);
init();
for(int i = ; i < E; i++){
char ch;
int u,v; scanf("%d %d %c",&u,&v,&ch);
if(ch == 'U'){
AddEdge(u,v,);
}else {
D[u].PB(v);
}
if(!vis[u]) cnt++,vis[u] = true;
if(!vis[v]) cnt++,vis[v] = true;
int s1 = Find(u),s2 = Find(v);
if(s1 != s2) {
cnt--;
pa[s1] = s2;
}
out[u]++; in[v]++;
}
return cnt == ;
} void reBuild()
{
for(int u = ; u <= V; u++){
for(int i = ; i < G[u].size(); i++){
Edge &e = edges[G[u][i]];
if(e.cap) {
int v0 = edges[G[u][i]^].v, v1 = e.v;
if(v0&&v0<=V&&v1&&v1<=V) D[v0].PB(v1);
}
}
}
} stack<int> ans;
void Euler(int u)
{
for(int &i = cur[u]; i < D[u].size();){
int v = D[u][i++];
Euler(v);
//printf("%d ",v);
ans.push(v);
}
} void solve()
{
if(read()) {
int totFlow = build();
if(~totFlow && totFlow <= MaxFlow()) {
reBuild();
memset(cur,,sizeof(int)*(vcnt));
Euler();
printf("");
while(ans.size()){
printf(" %d",ans.top());
ans.pop();
}
putchar('\n');
return;
}
}
puts("No euler circuit exist");
} int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int Test; scanf("%d",&Test); while(Test--){
solve();
if(Test) putchar('\n');
}
return ;
}
PS:
欧拉路径输出的套圈算法,进行了一点小小的优化,从dinic中收到启发改成了用数组cur[],这样可以节省判断vis的时间。
还有一个问题,此题是SJ,如下直接在dfs里逆序输出就WA。。。保存答案stack里输出才A,这样写有什么trick的情况吗?
void Euler(int u)
{
for(int &i = cur[u]; i < D[u].size();){
int v = D[u][i++];
Euler(v);
printf("%d ",v);
}
} 调用
memset(cur,,sizeof(int)*(vcnt));
Euler();
printf("1\n");
UVA 10735 Euler Circuit (最大流)的更多相关文章
- UVA 10735 Euler Circuit 混合图的欧拉回路(最大流,fluery算法)
题意:给一个图,图中有部分是向边,部分是无向边,要求判断是否存在欧拉回路,若存在,输出路径. 分析:欧拉回路的定义是,从某个点出发,每条边经过一次之后恰好回到出发点. 无向边同样只能走一次,只是不限制 ...
- UVa 10735 - Euler Circuit(最大流 + 欧拉回路)
链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- UVa 10735 (混合图的欧拉回路) Euler Circuit
题意: 给出一个图,有的边是有向边,有的是无向边.试找出一条欧拉回路. 分析: 按照往常的思维,遇到混合图,我们一般会把无向边拆成两条方向相反的有向边. 但是在这里却行不通了,因为拆成两条有向边的话, ...
- Euler Circuit UVA - 10735(混合图输出路径)
就是求混合图是否存在欧拉回路 如果存在则输出一组路径 (我就说嘛 咱的代码怎么可能错.....最后的输出格式竟然w了一天 我都没发现) 解析: 对于无向边定向建边放到网络流图中add(u, v, 1) ...
- 紫书 例题 11-13 UVa 10735(混合图的欧拉回路)(最大流)
这道题写了两个多小时-- 首先讲一下怎么建模 我们的目的是让所有点的出度等于入度 那么我们可以把点分为两部分, 一部分出度大于入度, 一部分入度大于出度 那么显然, 按照书里的思路,将边方向后,就相当 ...
- UVA LIVE-3263 - That Nice Euler Circuit
画一个顶点为偶数的封闭的二维图,当然.这个图能够自交,给出画的过程中的一些轨迹点.求出这个图把二次元分成了几部分,比如三角形把二次元分成了两部分. 这个的话,有图中顶点数+部分数-棱数=2的定律,这是 ...
- Uva 1342 - That Nice Euler Circuit
Little Joey invented a scrabble machine that he called Euler, after the great mathematician. In his ...
- UVA-10735 - Euler Circuit(混合欧拉回路输出)
题意:给你一个图,有N个点,M条边,这M条边有的是单向的,有的是双向的. 问你能否找出一条欧拉回路,使得每条边都只经过一次! 分析: 下面转自别人的题解: 把该图的无向边随便定向,然后计算每个点的入度 ...
- poj2284 That Nice Euler Circuit(欧拉公式)
题目链接:poj2284 That Nice Euler Circuit 欧拉公式:如果G是一个阶为n,边数为m且含有r个区域的连通平面图,则有恒等式:n-m+r=2. 欧拉公式的推广: 对于具有k( ...
随机推荐
- lua面向对象实现(实例化对象、继承、多态、多继承、单例模式)
lua面向对象实现: 一个类就像是一个创建对象的模具.有些面向对象语言提供了类的概念,在这些语言中每个对象都是某个特定类的实例.lua则没有类的概念,每个对象只能自定义行为和形态.不过,要在lua中模 ...
- npm 的安装与使用
创建: 2019/04/06 完成: 2019/04/07 安装 npm写在node.js里, 故安装node.js即可 https://nodejs.org/en/download/ 确认是否安装 ...
- 运行程序时抛出异常“找不到请求的 .Net Framework Data Provider。可能没有安装。”
方法1 如果系统未安装Oracle Data Provider 请参考方法2 右键单击项目,选择属性,切换到“生成”选项卡,将目标平台改为 Any CPU,并勾选“首选32位” 方法2 安装 Orac ...
- laravel 布局 详解(实例)
在resources/views里创建layouts,并在layouts里创建app.blade.php, 这个php文件放的就是你的页面框架,也就是多页面公用的内容,如下 <!DOCTYPE ...
- 笔记-JavaWeb学习之旅12
会话技术 Cookie:客户端会话技术,将数据保存到客户端 package com.data.Cookie; import javax.servlet.ServletException; import ...
- UINavigationController 的一些坑
坑一:自定义导航栏返回键 iOS7及之后版本 手势边缘右滑返回失效 解决方案: -(void)viewDidLoad{ [super viewDidLoad]; //self 为 UINavigati ...
- TYVJ1432 楼兰图腾
Description 平面上有 N(N≤[10]^5 ) 个点,每个点的横.纵坐标的范围都是 1~N,任意两个点的横.纵坐标都不相同.若三个点 (x_1,y_1),(x_2,y_2),(x_3,y_ ...
- 根据日期计算发布时间段(NSCalendar)
// 返回发布时间dateWithString - (NSString *)backReleaseTimeWithDateStr:(NSString *)dateWithString{ // 获取当前 ...
- LCT 学习笔记
LCT学习笔记 前言 自己定的学习计划看起来完不成了(两天没学东西,全在补题),决定赶快学点东西 于是就学LCT了 简介 Link/Cut Tree是一种数据结构,我们用它解决动态树问题 但是LCT不 ...
- JavaScript Allongé 第一呷 :基础函数 (2)
啊!我想要有一个参数 到现在为止,我们已经了解了没有参数的函数.只说我们的函数没有任何参数,甚至还没说参数是什么.大多数程序员非常熟悉参数,中学数学就讨论这个了.所以你知道他们是什么,而我也知道你知道 ...