AGC010F 题解
现在也就会写一写代码长度不超过 \(1k\) 的题目了。 /kk
看上去一脸不可做,看到 从必败状态逆推 的提示后会了。
考虑什么算是必败状态,我们设此时棋子所在的位置为 \(now\) 。
那么可以发现,当对于所有的 \(t\) 存在 \(now\rightarrow t\) 这条边,都满足 \(A_{now}\leq A_t\) 时,在 \(t\) 点一定是必败的。
原因显然,因为对于上述的情况,一但我把棋子从 \(now\) 移走,对手就会把它移回到 \(now\) 点,然后我就寄了。
我们考虑把眼光放低,着重去看一次移棋子的操作,容易发现当 \(A_{now}\leq A_t\) 时我把棋子从 \(now\) 移到 \(t\) 是不能做的。
原因是一样的,因为对手仍然可以把我赶回 \(now\) 。
所以可以看出你一条边是不可能从不同方向经过两次,也就是说在树中不能走回头路。
那我们直接令 \(i\) 为根节点,跑 \(n\) 遍 \(\text{DFS}\) ,复杂度 \(O(n^2)\) 。
代码只有 800B ,小学生写不出来的话幼儿园都会写。。。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
const int N = 5005;
int n, a[N], flag[N];
std::vector <int> dis[N];
inline void dfs(int now, int father) {
for (int t : dis[now]) {
if (t == father) continue;
dfs(t, now);
if (flag[t] == 0 && a[now] > a[t])
flag[now] = 1;
}
}
signed main(void) {
std::cin >> n;
for (int i = 1; i <= n; i++) std::cin >> a[i];
for (int i = 1, x, y; i < n; i++) {
scanf("%d %d", &x, &y);
dis[x].emplace_back(y);
dis[y].emplace_back(x);
}
for (int i = 1; i <= n; i++) {
memset(flag, 0, sizeof(flag));
dfs(i, 0);
if (flag[i] == 1)
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}