「CF858F」 Wizard's Tour

传送门
Luogu

解题思路

首先对于树的情况,我们很显然有一种贪心策略:
对于每一个节点先匹配子树,然后在还可以匹配的儿子间尽可能匹配,要是多出来一个就往上匹配。
推广到图的情况。。。
我们在图的生成树上 \(\text{DFS}\) ,即时删边,防止重复访问。
然后记录一个 \(f[x]\),表示直接与 \(x\) 节点并且还可以用来匹配的点。
那么我们直接一边 \(\text{DFS}\) ,一边匹配就好了。
最后输出答案即可。

细节注意事项

  • 没什么细节,就是要仔细想一想

参考代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#include <set>
#define rg register
#define file(x)                                 \
    freopen(x".in", "r", stdin);                \
    freopen(x".out", "w", stdout);
using namespace std;
template < typename T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while (!isdigit(c)) f |= (c == '-'), c = getchar();
    while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
    s = f ? -s : s;
}

const int _ = 200010;
const int __ = 400010;

int tot = 1, head[_], nxt[__], ver[__];
inline void Add_edge(int u, int v)
{ nxt[++tot] = head[u], head[u] = tot, ver[tot] = v; }

int n, m, vis[_] = { 1 }, f[_];
int cnt; struct node{ int x, y, z; }t[_];

inline void dfs(int u) {
    vis[u] = 1;
    for (rg int v, i = head[u]; i; i = nxt[i]) {
        v = ver[i], ver[i] = ver[i ^ 1] = 0;
        if (v != 0) {
            if (!vis[v]) dfs(v);
            if (f[v]) t[++cnt] = (node) { u, v, f[v] }, f[v] = 0;
            else if (f[u]) t[++cnt] = (node) { f[u], u, v }, f[u] = 0;
            else f[u] = v;
        }
    }
}

int main() {
    read(n), read(m);
    for (rg int u, v, i = 1; i <= m; ++i)
        read(u), read(v), Add_edge(u, v), Add_edge(v, u);
    for (rg int i = 1; i <= n; ++i) if (!vis[i]) dfs(i);
    printf("%d\n", cnt);
    for (rg int i = 1; i <= cnt; ++i)
        printf("%d %d %d\n", t[i].x, t[i].y, t[i].z);
    return 0;
}

完结撒花 \(qwq\)

猜你喜欢

转载自www.cnblogs.com/zsbzsb/p/11745839.html