Description
给一个无向图,$n$ 个点 $m$ 条边,给定一个 01 序列,如果 $a_i=1$,要求走到这个点奇数次,否则,要求走到这个点偶数次,请你任选起点,输出满足要求的经过点的序列和序列长度,序列长度不能超过 $4n$。
Solution
没思路的时候看到 CF 标签上的 “DFS”,于是考虑乱搞,然后就搞出来了。
首先任选一个要求走奇数遍的一个点进行 DFS。我们先不考虑图的形状,找一棵 DFS 树出来,然后遍历,如果回溯的时候发现这个点的奇偶性不对,我们走到它的父亲,再走回来,这样奇偶性就对了。然后一算:遍历 $2n$,处理一个奇偶性错误需要走 $2$ 个点,上界 $4n$,于是这道题就做完了。
注意到不一定是个联通图,那么考虑如果一个联通块内全是偶数,我们直接不走即可;如果存在奇数,那么必须走。
那么当有超过一个联通快内有奇数时,无解。
小问题:如果选择的根奇偶性不对,我们先正常改,然后把答案减掉 $3$ 即可(即不走回到根节点)。
Code
存答案的时候建议用 vector
而不是数组,我一开始忘记了 $4n$ 这回事导致 RE。
#include <cstdio>
#include <iostream>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
const int maxn = 1e5 + 10;
int a[maxn], ans[maxn * 4], father[maxn], vis[maxn], m, n, now[maxn];
int cnt = 0;
std::vector<int> e[maxn];
inline void add(int x, int y) { e[x].push_back(y), e[y].push_back(x); }
void dfs(int x, int fa)
{
vis[x] = 1, father[x] = fa;
ans[++cnt] = x, now[x] ^= 1;
for (int v : e[x])
{
if (vis[v])
continue;
dfs(v, x);
ans[++cnt] = x, now[x] ^= 1;
}
if (now[x] != a[x])
{
ans[++cnt] = fa;
ans[++cnt] = x;
now[x] ^= 1, now[fa] ^= 1;
}
}
int main()
{
std::ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 0, x, y; i < m; i++)
cin >> x >> y, add(x, y);
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
if (a[i] == 1)
{
dfs(i, 0);
break;
}
for (int i = 1; i <= n; i++)
if (!vis[i] && a[i])
{
cout << -1 << endl;
return 0;
}
if (ans[cnt - 1] == 0 && cnt >= 3)
cnt -= 3;
cout << cnt << endl;
for (int i = 1; i <= cnt; i++)
cout << ans[i] << (i == cnt ? "\n" : " ");
}