• UOJ 117 欧拉回路


    嘟嘟嘟

    正如题目所述,这就是一道板子题。

    不过身为一道板子题,数据还是非常负(du)责(liu)的。

    一点点讲。

    1.判断欧拉图

      判断无向图是欧拉图就是所有点的度数都是偶数;判断有向图是欧拉图就是所有点的入度等于出度。

      但是仅这样是不行的,还有判断图是否连通。这个可以用并查集实现。或者是看dfs经过的所有边是否等于m。

    2.求欧拉回路

      对于一个点x,如果有一条边(x->y)没走过,就接着dfs(y),并把(x->y)加入记录答案的栈中。最后倒序输出。

      所以要有一个标记数组。

      对于无向图,建图的时候是把(x, y)拆成(x->y)和(y->x)两条边,因此标记的时候我们要一次把两条边都标记了。不过有一个更简便的方法:两条边的编号一定是e和e + 1,虽然边存了双倍,但是标记的时候只用标记e >> 1,判断的时候对于e和e +1,都判断e >> 1是否走过即可。因此,ecnt要从2开始计数,所以初始化ecnt = 1。

      对于有向图,如果只想写一遍dfs,开一个标记数组的话,可以模仿无向图的存边方式,隔一个一存,这样就和无向图统一了。

      朴素的dfs会TLE,因此每一个点要加上弧优化。在保证正确性的前提下较简洁的写法请看下面的代码。

      duliu的数据告诉我们1~n中有些点可能不存在,所以不能默认从1开始dfs。所以再开一个变量s,存图中存在的任意一个点,然后从dfs(s)开始即可。可是数据过分的负责,有m = 0的点,所以s一定要赋初值0,这样dfs(0)什么也没有就退出来了,防止因s没赋初值而不知道从哪儿开始dfs然后RE。

    3.输出答案

      在代码中ans存的是双倍的边的编号。如果ans[i]是奇数编号,那么一定是人为添加的反向边,输出-(ans[i] >> 1),否则输出正的。

    4.祝Debug愉快。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 1e5 + 5;
    21 const int maxm = 2e5 + 5;
    22 inline ll read()
    23 {
    24     ll ans = 0;
    25     char ch = getchar(), last = ' ';
    26     while(!isdigit(ch)) {last = ch; ch = getchar();}
    27     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    28     if(last == '-') ans = -ans;
    29     return ans;
    30 }
    31 inline void write(ll x)
    32 {
    33     if(x < 0) x = -x, putchar('-');
    34     if(x >= 10) write(x / 10);
    35     putchar(x % 10 + '0');
    36 }
    37 
    38 int n, m;
    39 struct Edge
    40 {
    41     int to, nxt;
    42 }e[maxm << 1];
    43 int head[maxn], ecnt = 1;
    44 void addEdge(int x, int y)
    45 {
    46     e[++ecnt] = (Edge){y, head[x]};
    47     head[x] = ecnt;
    48 }
    49 
    50 int ans[maxm << 1], cnt = 0;
    51 bool vis[maxm];
    52 int in[maxn], out[maxn];
    53 void dfs(int now)
    54 {
    55     for(int &i = head[now]; i; i = e[i].nxt)
    56     {
    57         int tp = i;
    58         if(!vis[tp >> 1])
    59         {
    60             vis[tp >> 1] = 1;
    61             dfs(e[tp].to);
    62             ans[++cnt] = tp;
    63         }
    64     }
    65 }
    66 
    67 int main()
    68 {
    69     int s = 0, t = read();
    70     n = read(); m = read();
    71     for(int i = 1; i <= m; ++i)
    72     {
    73         int x = read(), y = read();
    74         s = x;
    75         addEdge(x, y);
    76         if(t == 1) addEdge(y, x), in[x]++, in[y]++;
    77         else ecnt++, out[x]++, in[y]++;
    78     }
    79     if(t == 1)
    80     {
    81         for(int i = 1; i <= n; ++i)
    82             if(in[i] & 1) {puts("NO"); return 0;}
    83     }
    84     else
    85     {
    86         for(int i = 1; i <= n; ++i)
    87             if(in[i] != out[i]) {puts("NO"); return 0;}
    88     }
    89     dfs(s);
    90     if(cnt != m) puts("NO");
    91     else
    92     {
    93         puts("YES");
    94         for(int i = cnt; i; --i) write((ans[i] & 1) ? -(ans[i] >> 1) : (ans[i] >> 1)), space;
    95         enter;
    96     }
    97     return 0;
    98 }
    View Code
  • 相关阅读:
    C++ Primer Plus章节编程练习(第十章)
    Bezier曲线
    C++静态持续变量
    计算机图形学之三维图形变换
    计算机图形学之二维图形变换
    C++ Primer Plus章节编程练习(第七章)
    C++中的指针与const
    Java 输入输出流
    Java Fx 画圆环
    注册事件及事件处理
  • 原文地址:https://www.cnblogs.com/mrclr/p/9763730.html
Copyright © 2020-2023  润新知