UVA 10735 混合图的欧拉回路

题意:

判断混合图中是否存在欧拉回路,如果存在欧拉回路,输出路径。

思路:

欧拉回路 存在每条边经过且只经过一次后回到原点的路径

在混合图中存在欧拉回路,需要满足以下条件:

1.把所有无向边任意规定一个方向后,对于每个点,满足 |入度-出度| % 2 == 0

2.按照上面已经规定的方向,利用 无向边 建图(有向边忽略掉),然后对于每个结点u,如果in[u]<out[u], 建边(s, u, |入度-出度| / 2);如果in[u]>out[u], 建边(u, t, |入度-出度| / 2)

括号中的内容分别是 (起点,终点,容量)

3.新建的图G‘中找最大流,如果满流就说明欧拉回路是存在的~

欧拉回路的输出我感觉挺难想的。。我太弱了吧.....T_T

就是把所有用到的边都存下来~(原图中的有向边必然要存下来),但是对于原图中的无向边,我们要根据刚才最大流时每条边中的流量关系来确定其方向:如果规定方向后,跑出最大流时这条无向边中有流量,说明要将这条边反向~

然后利用某个算法(见代码)~~来把欧拉回路找粗来。。。

code:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#include<cstdlib>
using namespace std;

#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))

typedef pair<int,int> pii;
typedef long long LL;
//------------------------------
const int maxn = 205;

int n,m;

struct Edge{
      int to, cap, rev;//终点 容量 反向边
      Edge(int to_ = 0, int cap_ = 0, int rev_ = 0){
            to = to_;
            cap = cap_;
            rev = rev_;
      }
};
vector<Edge> g[maxn], qg[maxn];//qg[maxn]是欧拉回路用到的边
int level[maxn];//顶点到源点的距离标号
int iter[maxn];

void add(int from, int to){//欧拉回路用到的边
      Edge tmp1(to, 0, qg[to].size());
      qg[from].push_back(tmp1);
}

void add_Edge(int from, int to, int cap){
      Edge tmp1(to, cap, g[to].size());
      g[from].push_back(tmp1);
      Edge tmp2(from, 0, g[from].size()-1);
      g[to].push_back(tmp2);
}
void bfs(int s){
      memset(level, -1, sizeof(level));
      queue<int> q;
      level[s] = 0;
      q.push(s);
      while(!q.empty()){
            int v = q.front();
            q.pop();
            for(int i = 0; i < g[v].size(); i++){
                  Edge& e = g[v][i];
                  if(e.cap > 0 && level[e.to] < 0){
                  level[e.to] = level[v] + 1;
                  q.push(e.to);
                  }
            }
      }
}
int dfs(int v, int t, int f){
      if(v == t) return f;
      for(int& i = iter[v]; i < g[v].size(); i++){
            Edge& e = g[v][i];
            if(e.cap > 0 && level[v] < level[e.to]){
                  int d = dfs(e.to, t, min(e.cap, f));
                  if(d > 0){
                        e.cap -= d;
                        g[e.to][e.rev].cap += d;
                        return d;
                  }
            }
      }
      return 0;
}
int max_flow(int s, int t){
      int flow = 0;
      for(;;){
            bfs(s);
            if(level[t] < 0) return flow;
            memset(iter, 0, sizeof(iter));
            int f;
            while((f = dfs(s, t, INF)) > 0){
                  flow += f;
            }
      }
}
//------------------上面是最大流模板部分 正确----------------------

int in[maxn], out[maxn];

int put[1000005];
int cnt = 0;
void print(int u){                  //打印欧拉回路
      for(int i = 0; i < qg[u].size(); i++){
            Edge& et = qg[u][i];
            if(!et.cap){
                  et.cap = 1;
                  print(et.to);
            }
      }
      put[cnt++] = u;
}
void init(){
      memset(G, 0, sizeof(G));
      memset(in, 0, sizeof(in));
      memset(out, 0, sizeof(out));
      for(int i = 0; i < maxn; i++) g[i].clear();
      for(int i = 0; i < maxn; i++) qg[i].clear();

      n = Scan(); m = Scan();
      int u, v;
      char s[10];
      for(int i = 1; i <= m; i++){
            u = Scan();
            v = Scan();
            scanf("%s", s);
            if(s[0] == 'U'){
                  add_Edge(u, v, 1);
            }
            else {
                  add(u, v);
            }
            out[u] ++;
            in[v] ++;
      }
}
void solve(){
      for(int i = 1; i <= n; i++){
            if(abs(out[i] - in[i]) % 2){
                  printf("No euler circuit exist\n");
                  return;
            }
      }
      int sumv = 0;
      for(int i = 1; i <= n; i++){
            if(in[i] < out[i]){
                  add_Edge(0 , i, (out[i] - in[i]) / 2);
                  sumv += (out[i] - in[i])/2;
            }
            else if(out[i] < in[i]){
                  add_Edge(i, n+1, (in[i] - out[i]) / 2);
            }
      }

      int ans = max_flow(0, n+1);
      if(ans != sumv){
            printf("No euler circuit exist\n");
            return;
      }

      for(int i = 1; i <= n; i++){
            for(int j = 0; j < g[i].size(); j++){
                  Edge et = g[i][j];
                  int v = et.to;
                  if(v == 0 || v == n+1 || !et.cap) continue; //建立了双向边,所以cap!=0的边说明其反向边中有流量,所以其实应该增加这条边
                  add(i, v);
            }
      }
      cnt = 0;
      print(1);
      for(int i = cnt - 1; ~i; --i) printf("%d%c", put[i], i ? ' ' : '\n');
}
int main(){
      int t;
      scanf("%d",&t);
      while(t--){
            init();
            solve();
            if(t != 0) printf("\n");
      }
      return 0;
}

反正我判断是不是欧拉回路的时候用的时间很少的,我干囧好简单...但是我刚开始的时候并不会输出路径撒....sigh..

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-08 10:34:35

UVA 10735 混合图的欧拉回路的相关文章

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

题意: 给出一个图,有的边是有向边,有的是无向边.试找出一条欧拉回路. 分析: 按照往常的思维,遇到混合图,我们一般会把无向边拆成两条方向相反的有向边. 但是在这里却行不通了,因为拆成两条有向边的话,就表示这个边能“在两个相反方向各经过一次”. 而题意是这个边只能经过一次. 假设图中存在欧拉回路,则所有点的出度out(i) 等于 入度in(i) 不妨这样,先将所有的无向边任意定向,对于out(u) > in(u)的点,可以将已经定向的无向边u->v反向为v->u,这样out(u) - i

UVA 10735 混合图的欧拉回路+输出路径

#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #include<string> #define eps 1e-12 #define I

POJ 1637 Sightseeing tour(混合图的欧拉回路)

题目链接 建个图,套个模板. #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <algorithm> #include <vector> #include <string> #include <queue> using namespace std; #define INF 0x3ffffff str

poj1637 Sightseeing tour,混合图的欧拉回路问题,最大流解

混合图的欧拉回路问题 题目地址 欧拉回路问题 1 定义 欧拉通路 (Euler tour)--通过图中每条边一次且仅一次,并且过每一顶点的通路. 欧拉回路 (Euler  circuit)--通过图中每条边一次且仅一次,并且过每一顶点的回路. 欧拉图--存在欧拉回路的图.  2 无向图是否具有欧拉通路或回路的判定  G有欧拉通路的充分必要条件为:G 连通,G中只有两个奇度顶点(它们分别是欧拉通路的两个端点). G有欧拉回路(G为欧拉图):G连通,G中均为偶度顶点.  3 有向图是否具有欧拉通路或

bzoj2095: [Poi2010]Bridges(二分+混合图求欧拉回路)

传送门 这篇题解讲的真吼->这里 首先我们可以二分一个答案,然后把所有权值小于这个答案的都加入图中 那么问题就转化为一张混合图(既有有向边又有无向边)中是否存在欧拉回路 首先 无向图存在欧拉回路,当且仅当图的所有顶点度数都为偶数且图连通.        有向图存在欧拉回路,当且仅当图的所有顶点入度等于出度且图连通. 那么我们怎么判断混合图的欧拉回路是否存在呢? 我们把无向边的边随便定向,然后计算每一个点的入度和出度.如果有某一个点的入度和出度之差是奇数,那么肯定不存在欧拉回路. 因为欧拉回路要求

欧拉回路、混合图的欧拉回路

欧拉回路 从一个点开始把图中的边恰好经过一次,再回到出发点,这样的路径就是欧拉回路. 如图就是一个欧拉回路 欧拉回路判定 不过怎么样的图中才存在欧拉回路呢? 欧拉回路分有向图和无向图两种: 有向图: 图中所有点的入度等于出度 无向图: 图中所有点的度数都为偶数 这还是很好理解的,不过你可能要问,怎么知道一个混合图中有没有欧拉回路呢? 混合图的欧拉回路 过程: 先将无向边随意定向 判断每个点的入度和出度是不是同奇偶,不同则无解 用一个超级原点向出度小于入度的点连一条容量为 \({|入度-出度| \

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

题意:给一个图,图中有部分是向边,部分是无向边,要求判断是否存在欧拉回路,若存在,输出路径. 分析:欧拉回路的定义是,从某个点出发,每条边经过一次之后恰好回到出发点. 无向边同样只能走一次,只是不限制方向而已,那么这个情况下就不能拆边.不妨先按照所给的start和end的顺序,初步定下该无向边的顺序(若不当,一会再改).那么有个问题,我们需要先判断其是否存在欧拉回路先. 混合图不满足欧拉回路因素有:(1)一个点的度(无论有无向)是奇数的,那么其肯定不能满足出边数等于入边数.(2)有向边的出入度过

混合图的欧拉回路判定

对于有向图和无向图的欧拉回路判定,很容易做到.那对于混合图呢?? 混合图就是图中既存在无向边又存在有向边的图. 至于解法: 转载自这里 把该图的无向边随便定向,计算每个点的入度和出度.如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路.因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路. 好了,现在每个点入度和出度之差均为偶数.那么将这个偶数除以2,得x.也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出 = 入.如果

POJ 1637 混合图的欧拉回路判定

题意:一张混合图,判断是否存在欧拉回路. 分析参考: 混合图(既有有向边又有无向边的图)中欧拉环.欧拉路径的判定需要借助网络流! (1)欧拉环的判定:一开始当然是判断原图的基图是否连通,若不连通则一定不存在欧拉环或欧拉路径(不考虑度数为0的点). 其实,难点在于图中的无向边,需要对所有的无向边定向(指定一个方向,使之变为有向边),使整个图变成一个有向欧拉图(或有向半欧拉图).若存在一个定向满足此条件,则原图是欧拉图(或半欧拉图)否则不是.关键就是如何定向? 首先给原图中的每条无向边随便指定一个方