题意:求混合图的欧拉路径。

一句话总结:网络流,最主要在于建图,此题是将出度则是和流量联系在了一起,用最大流来调整边的指向。

分析:

这题的困难之处在于无向边只能用一次,相当于一个方向未定的有向边。

首先用并查集判断图的连通性,(直接计数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 (最大流)的更多相关文章

  1. UVA 10735 Euler Circuit 混合图的欧拉回路(最大流,fluery算法)

    题意:给一个图,图中有部分是向边,部分是无向边,要求判断是否存在欧拉回路,若存在,输出路径. 分析:欧拉回路的定义是,从某个点出发,每条边经过一次之后恰好回到出发点. 无向边同样只能走一次,只是不限制 ...

  2. UVa 10735 - Euler Circuit(最大流 + 欧拉回路)

    链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  3. UVa 10735 (混合图的欧拉回路) Euler Circuit

    题意: 给出一个图,有的边是有向边,有的是无向边.试找出一条欧拉回路. 分析: 按照往常的思维,遇到混合图,我们一般会把无向边拆成两条方向相反的有向边. 但是在这里却行不通了,因为拆成两条有向边的话, ...

  4. Euler Circuit UVA - 10735(混合图输出路径)

    就是求混合图是否存在欧拉回路 如果存在则输出一组路径 (我就说嘛 咱的代码怎么可能错.....最后的输出格式竟然w了一天 我都没发现) 解析: 对于无向边定向建边放到网络流图中add(u, v, 1) ...

  5. 紫书 例题 11-13 UVa 10735(混合图的欧拉回路)(最大流)

    这道题写了两个多小时-- 首先讲一下怎么建模 我们的目的是让所有点的出度等于入度 那么我们可以把点分为两部分, 一部分出度大于入度, 一部分入度大于出度 那么显然, 按照书里的思路,将边方向后,就相当 ...

  6. UVA LIVE-3263 - That Nice Euler Circuit

    画一个顶点为偶数的封闭的二维图,当然.这个图能够自交,给出画的过程中的一些轨迹点.求出这个图把二次元分成了几部分,比如三角形把二次元分成了两部分. 这个的话,有图中顶点数+部分数-棱数=2的定律,这是 ...

  7. Uva 1342 - That Nice Euler Circuit

    Little Joey invented a scrabble machine that he called Euler, after the great mathematician. In his ...

  8. UVA-10735 - Euler Circuit(混合欧拉回路输出)

    题意:给你一个图,有N个点,M条边,这M条边有的是单向的,有的是双向的. 问你能否找出一条欧拉回路,使得每条边都只经过一次! 分析: 下面转自别人的题解: 把该图的无向边随便定向,然后计算每个点的入度 ...

  9. poj2284 That Nice Euler Circuit(欧拉公式)

    题目链接:poj2284 That Nice Euler Circuit 欧拉公式:如果G是一个阶为n,边数为m且含有r个区域的连通平面图,则有恒等式:n-m+r=2. 欧拉公式的推广: 对于具有k( ...

随机推荐

  1. 爬虫中Xpath有时候是无效的

    http://www.cnblogs.com/lchzls/p/6282790.html给出了两种方案

  2. C# 获取汉字的拼音首字母和全拼(含源码)

    C# 获取汉字的拼音首字母 一种是把所有中文字符集合起来组成一个对照表:另一种是依照汉字在Unicode编码表中的排序来确定拼音的首字母.碰到多音字时就以常用的为准(第一种方法中可以自行更改,方法为手 ...

  3. MySQL备份与主备配置

    MySQL备份与主备配置 数据备份类型 全量备份:备份整个数据库 增量备份:备份自上一次备份以来(增量或完全)以来变化的数据 差异备份:备份自上一次完全备份以来变化的数据 全量备份 全量备份的方法有 ...

  4. vue.eslintrc.js常用配置

    vue.eslintrc.js module.exports = { root: true, env: { node: true }, extends: [ "plugin:vue/esse ...

  5. 洛谷 - P2051 - 中国象棋 - 简单dp

    https://www.luogu.org/problemnew/show/P2051 一点都不简单的简单dp. 还是从旧行转移到新行,而不是考虑新行从哪些旧行转移吧. #include<bit ...

  6. Codeforces Round #439 (Div. 2)C - The Intriguing Obsession(简单dp)

    传送门 题意 给出三个集合,每个集合的元素数量为a,b,c,现在需要连边,满足集合内元素不可达或最短路为3,求可行方案数 分析 设dp[i][j]为a集合元素为i个,b集合元素为j个的可行方案,易知( ...

  7. lightoj1087 【线段树】

    题意: 给你n个数,然后给你q个询问,有两种询问: a: 表示在右边插入一个数 c:表示从左边拿出一个数,然后输出: 思路: 一开始在想,自己手上的黑科技:线段树和树状数组 线段树上的操作: 求区间最 ...

  8. 計蒜客/小教官(xjb)

    題目鏈接:https://nanti.jisuanke.com/t/366 題意:中文題誒~ 思路: 先通過給出的條件構造一個符合題意的數組(可以是任意一個符合條件的數組,菜雞不會證明: 然後構造的數 ...

  9. 洛谷P3312 [SDOI2014]数表(莫比乌斯反演+树状数组)

    传送门 不考虑$a$的影响 设$f(i)$为$i$的约数和 $$ans=\sum\limits_{i=1}^n\sum\limits_{j=1}^nf(gcd(i,j))$$ $$=\sum\limi ...

  10. [SDOI2019] 热闹又尴尬的聚会

    热闹度\(p\)子图中最小的度数,尴尬度\(q\)独立集大小,之间的约束 \[ \begin{aligned} \lfloor n/(p+1)\rfloor\le q &\rightarrow ...