Miner(欧拉路径)

Description:

这里写图片描述

题解:

mdzz今天肝c两小时因为copy错了样例,最后被卡常,a没拍直接爆了,b还没时间想,其实是最简单的。

对于每一个连通块单独考虑。

一个联通块度数为奇数的点肯定是偶数个的,那么用欧拉路径去覆盖这个联通块最少就需要 2 度 数 为 奇 数 的 点 个 数 2

考虑如何找到这些路径?

建立超级源,向每个奇点连边,从这个点开始,跑欧拉回路,最后被这个点分隔开的就是那些路径了。

现在难点在于删边,这是个无向图,一条边被删的话,其对应的那条反向边也要删掉,这个不用真的删掉,打个标记,在以后用到那条边的时候直接跳过就行了,注意code里的打法。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define pb push_back
using namespace std;

const int N = 4e5 + 5;

int n, m, x, y, td, r[N], f[N], d[N], p[N];

int fi(int x) { return f[x] == x ? x : (f[x] = fi(f[x]));}

int final[N], to[N], next[N], tot = 1, bz[N];
void link(int x, int y) {
    next[++ tot] = final[x], to[tot] = y, final[x] = tot;
}

struct edge {
    int final[N], to[N], next[N], tot;
    void link(int x, int y) { next[++ tot] = final[x], to[tot] = y, final[x] = tot;}
} e;

void dg(int x) {
    for(int i = final[x]; i; i = final[x]) {
        final[x] = next[i];
        if(bz[i]) continue;
        bz[i] = bz[i ^ 1] = 1;
        dg(to[i]);
    }
    p[++ p[0]] = x;
}

vector<int> b[N]; int tb;

int main() {
    freopen("miner.in", "r", stdin);
    freopen("miner.out", "w", stdout);
    scanf("%d %d", &n, &m);
    fo(i, 1, n) f[i] = i;
    fo(i, 1, m) {
        scanf("%d %d", &x, &y);
        r[x] ++; r[y] ++;
        link(x, y); link(y, x);
        if(fi(x) != fi(y)) f[f[x]] = f[y];
    }
    fo(i, 1, n) if(r[i]) e.link(fi(i), i);
    td = n;
    fo(i, 1, n) if(e.final[i]) {
        d[0] = p[0] = 0;
        for(int j = e.final[i]; j; j = e.next[j])
            d[++ d[0]] = e.to[j];
        td ++; int hh = 0;
        fo(j, 1, d[0]) if(r[d[j]] & 1)
            link(td, d[j]), link(d[j], td), hh ++;
        if(hh) dg(td); else dg(i);
        int la = 0; p[p[0] + 1] = n + 1;
        fo(j, 1, p[0] + 1) if(p[j] > n) {
            if(la < j - 1) {
                b[++ tb].pb(j - la - 1);
                fo(k, la + 1, j - 1) b[tb].pb(p[k]);
            }
            la = j;
        }
    }
    printf("%d\n", tb - 1);
    printf("%d\n", b[1][1]);
    fo(i, 2, b[1][0]) printf("0 %d\n", b[1][i]);
    fo(j, 2, tb) {
        printf("1 %d\n", b[j][1]);
        fo(i, 2, b[j][0]) printf("0 %d\n", b[j][i]);
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值