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..

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值