• 0925考试T2 欧拉回路


    0925考试T2

    ​ 题目大意:

    ​ 给定一个任意的无向图,问最少画几笔,使得所有的边被画过一次且仅一次。

    ​ 欧拉回路。

    ​ 我们称有偶数条边连着的点叫偶数点,有奇数条边连着的点叫奇数点。

    ​ 欧拉路:有一条路径可以经过所有边并且不重复。欧拉回路:闭合的欧拉路。

    ​ 首先我们要知道:无向图中存在欧拉回路的条件是所有点都是偶数点,因为有进就有出嘛。

    ​ 对于这个题,有好多个联通块,每个联通块是一个无向图,每个联通块的答案是独立的。对于某个无向图既有奇数点又有偶数点,我们可以把所有奇数点变为偶数点。把奇数点变为偶数点肯定要加边,我们把这些边标记一下,相当于在整个欧拉回路里是一个断点,就是由这些新加的边确定到底要画几笔。

    ​ 那具体怎么加呢?我们让奇数点之间两两连边,至少要加(max(frac{k}{2}, 1))条边,(k)是奇数点的个数,因为每加一条边就会消去两个奇数点。把这些加的边叫做虚边。

    ​ 我们在(dfs)的时候,遇到一条边就标记一条,表示下次不会搜这条边了。如果碰到一个虚边,我们就让次数加一。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline double read() {
        double s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s * 10) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 1e5 + 5;
    int T, n, m, cnt, tot;
    int vis[N], out[N], head[N];
    vector <int> a[N];
    struct edge { int f, to, id, nxt; } e[N << 3];
    
    void clear() {
        cnt = 1, tot = 0; //cnt = 1为了成对变换
        for(int i = 0;i <= n; i++) head[i] = vis[i] = out[i] = 0;
    }
    
    void add(int x, int y, int id) {
        e[++cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y; e[cnt].id = id; e[cnt].f = 0;
    }
    
    void dfs(int x) {
        vis[x] = 1;
        for(int i = head[x]; i ; i = e[i].nxt) {
            int y = e[i].to; int id = e[i].id;
            if(!e[i].f) {
                e[i].f = e[i ^ 1].f = 1; //将这条边和反向边标记
                dfs(y);
                if(id) a[tot].push_back(-id); //-id是为了输出顺序是对的
                else tot ++; //扫到虚边
            }
        }
    }
    
    int main() {
    
        T = read(); 
        while(T --> 0) {
            n = read(); m = read(); clear();
            for(int i = 1, x, y;i <= m; i++) {
                x = read(); y = read(); out[x] ++; out[y] ++;
                add(x, y, i); add(y, x, -i);
            }
    
            int last = 0;
            for(int i = 1;i <= n; i++) 
                if(out[i] & 1) 
                    if(last) {
                        add(last, i, 0); add(i, last, 0); last = 0;
                    } //奇数点两两连边
                    else last = i;
            
            for(int i = 1;i <= n; i++) 
                if(!vis[i] && (out[i] & 1)) {
                    tot ++; dfs(i); tot--; //因为虚边是最后一次加入的,tot会多加一次
                }
            
            for(int i = 1;i <= n; i++) 
                if(!vis[i] && out[i]) {
                    tot ++; dfs(i);
                }
            
            printf("%d
    ", tot - 1);
            for(int i = 1;i <= tot; i++) {
                printf("%d", (int)a[i].size());
                for(int j = 0;j < (int)a[i].size(); j++) 
                    printf(" %d", a[i][j]);
                printf("
    ");
                a[i].clear();
            }
        }
    
        fclose(stdin); fclose(stdout);
        return 0;
    }
    
  • 相关阅读:
    windows下基于IIS配置ssl证书
    IIS HTTP重定向到HTTPS
    C#:调用存储过程方法
    IIS无法启动解决方案
    C#工具:ASP.net 调用MySQL 帮助类(包括存储过程调用)
    C#工具:ASP.net 调用SQLserver帮助类
    HTTPClick调用WebApi帮助类
    三元运算符判断三种状态
    pandas模块
    numpy模块
  • 原文地址:https://www.cnblogs.com/czhui666/p/13733011.html
Copyright © 2020-2023  润新知