Codeforces 1586E. Moment of Bloom

博客主要探讨了Codeforces 1586E问题的解决方案,通过构造生成树并进行暴力路径操作来求解。作者证明了在树上操作的必要性和最优性,并提供了C++代码实现。文章强调了欧拉路径在证明中的作用,并展示了如何在生成树上找到最优路径组合。
摘要由CSDN通过智能技术生成

Codeforces 1586E. Moment of Bloom

思路

从原图构造任意生成树,在生成树上暴力即可,下证正确性。

首先证明,对于树,在操作后清除所有奇数边所需的次数是 s u m 2 \cfrac{sum}{2} 2sum ,其中 s u m sum sum 代表奇数节点个数 (注意,对于树来说,一对操作的路径是唯一的)

因为一次操作最多只能改变两个节点的奇偶性,全为偶数的必要条件为所有节点都为偶数,又由欧拉路径,总存在可行解,证毕

然后证明,任意原图的路径选择不会优于生成树上的路径选择

原图通过操作后,将得到的奇数边清除的次数下限亦为 s u m 2 \cfrac{sum}{2} 2sum ,原理同上

那么暴力的正确性证毕

代码

#include <bits/stdc++.h>
using namespace std;

typedef long double ld;
typedef long long ll;
typedef unsigned long long ull;
typedef const int& cint;
typedef pair<int, int> pii;

const int mod = 1e9+7;
const int inf_int = 0x7fffffff;
const int hf_int = 0x3f3f3f3f;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;

int n, m, qq;
vector<int> to[300300];
vector<int> ans[300300];
int sum[300300];
int up[300300];
int dep[300300];

void dfs(cint u, cint fa) {
    dep[u] = dep[fa] + 1;
    up[u] = fa;
    for(int v: to[u]) {
        if(v != fa && !dep[v]) {
            dfs(v, u);
        }
    }
}

int ss = 0;
void sol(cint u, cint fa) {
    if(sum[u]%2) ++ss;
    for(int v: to[u]) {
        if(v != fa && dep[v] == dep[u]+1) {
            sol(v, u);
        }
    }
}

int main() {
    //freopen("1.in", "r", stdin);
    //cout.flags(ios::fixed); cout.precision(8);
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n >> m;
    int u, v;
    for(int i=1; i<=m; i++) {
        cin >> u >> v;
        to[u].push_back(v);
        to[v].push_back(u);
    }
    dfs(1, 1);
    cin >> qq;
    for(int i=1; i<=qq; i++) {
        cin >> u >> v;
        vector<int> tmp;
        while(dep[v] > dep[u]) {
            tmp.push_back(v);
            v = up[v];
        }
        while(dep[u] > dep[v]) {
            ans[i].push_back(u);
            u = up[u];
        }
        while(u != v) {
            ans[i].push_back(u);
            tmp.push_back(v);
            u = up[u];
            v = up[v];
        }
        ans[i].push_back(u);
        for(int j=tmp.size()-1; j>=0; j--) ans[i].push_back(tmp[j]);
        for(int j=0; j<ans[i].size(); j++) {
            if(j != 0 && j != ans[i].size()-1) ++sum[ans[i][j]];
            ++sum[ans[i][j]];
        }
    }
    sol(1, 1);
    // cout << ss << endl;
    if(ss == 0) {
        cout << "YES" << endl;
        for(int i=1; i<=qq; i++) {
            cout << ans[i].size() << endl;
            for(int j: ans[i]) cout << j << ' ';
            cout << endl;
        }
    }
    else {
        cout << "NO" << endl;
        cout << ss/2 << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值