AtCoder-abc345_f 题解

题意简述

给定一个无向图。你要在其中选出一些边,使得选出的边所构成的图中,度数为奇数的点有 \(K\) 个。如果可以,输出选了哪些边,否则输出 -1

思路

首先在选一条边时,边两端点度数的奇偶性一定都会改变,即要么都变为奇数,要么两个点的奇偶性交换,要么都变为偶数。这三种情况时满足条件的点的个数分别变为 \(+2,0,-2\)。因此无论怎么选边,度数为奇数的点只能有偶数个。所以 \(K \equiv 1 \pmod 2\) 时一定无解。

题目没说图一定连通,所以我们需要对每个连通块分别处理。

假设这个连通块有 \(N\) 个节点,那么这个连通块在选边后最多能有几个点的度数为奇数呢?

答案是 \(N-(N \bmod 2)\),即不大于 \(N\) 的最大偶数。为什么呢?

我们先求出这个图的 DFS 树。此时树中有 \(N-1\) 条边。在 DFS 时,同时维护子树大小 \(sz\) 和搜索时该点度数的奇偶性 \(li\)(奇数为 \(true\),偶数为 \(false\))。

我们在遍历的时候,假设遍历到了 \(u \to v\) 这条边,\(u\) 的父亲是 \(f\)。如果 \(li_v=false\),就选择 \(u \to v\) 这条边,并把 \(li_v\) 标记为 \(true\)\(li_u\) 反转。便利完所有出边后,会有下面几种情况:

  • \(li_u=true\)

此时 \(u\) 已经满足条件了。回到 \(f\) 时,\(f \to u\) 的这条边不会被选。对 \(u\) 的搜索结束,\(u\) 可以满足条件。

  • \(li_u=false\)

此时 \(u\) 没有满足条件。那么在回到 \(f\) 时,则会选择 \(f \to u\) 这条边,使得 \(u\) 满足条件。

这么看来所有的点都会满足条件,除了根节点。如果 \(N \equiv 1 \pmod 2\),则除根节点之外的点都已经满足条件,根节点无法满足条件。否则根节点也可以满足条件。

我们在搜索的时候可以记录还需要让多少个点满足条件。设这个值为 \(w\)。那么我们在选边的时候,根据上面遍历到 \(u \to v\) 时的几种情况再做出相应做法:

  • \(w=0\)

这条边不选即可。

  • \(w>0\)

    • \(li_v=false\)

我们选择这条边,使得 \(v\) 满足了条件,\(w \gets w-1\)

接下来我们计算出 \(li_u\),如果为 \(true\),则该点由不满足条件变为满足条件,\(w \gets w-1\)。否则该点由满足条件变为不满足条件,\(w \gets w+1\)

    • \(li_v=true\)

这条边不选即可。

可以发现,在选择一条边后,\(w\) 值要么不变,要么 \(-2\)。这样最后如果 \(w=0\),则有解,否则无解。

到这里,最后一个问题就是记录选择哪些边了。我们可以使用链式前向星存图,因为是无向图,每个边存两次。我们可以从编号 \(2\) 开始存,第一条边的编号为 \(2,3\),第二条为 \(4,5\)。我们再用一个 \(ans\) 数组,如果这条边选了,我们把对应边编号的 \(ans\) 值设为 \(true\)。这样每条边编号除以二下取整就是它实际边的编号。

那么这个问题就解决了。

代码

posted @ 2024-03-17 11:26  lrx139  阅读(70)  评论(0编辑  收藏  举报