AT2307 题解

AT2307 题解

$\text{Description}$

给定一棵树,树有点权。两人博弈,先手方可指定初始棋子在某个节点上,然后两人交替进行:将棋子所在的点的点权减一,然后将棋子移到与棋子所在的点相邻的点上。先不能操作者失败。求所有作为棋子初始所在的节点时,先手有必胜策略的节点。

$n\le 3000$

$\text{Solution}$

容易想到枚举点分析可行性。

自下向上考虑只考虑每个节点的子树是先手必胜还是后手必胜。

容易发现叶节点后手必胜。

对于非叶子节点,容易发现不能向先手必胜的节点走,这意味着若所有儿子都是先手必胜的话,那么该节点后手必胜。

考虑一个后手必胜的儿子,我们走进去后,对方必定要走回来,否则就让我们胜利。

这意味着我们只会站在这个节点上,而对方只会站在儿子节点上。所以我们只要让当前节点的点权大于儿子节点的点权就是先手必胜。

$\text{Code}$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<bits/stdc++.h>
#define MAXN 3005
#define REG register
using namespace std;
inline void read(int& x){
static char c;
while(!isdigit(c=getchar()));x=c^48;
while(isdigit(c=getchar()))x=(x*10)+(c^48);
}

int n;

struct Edge{int v,nxt;}ed[MAXN<<1];
int head[MAXN],cnt;
inline void adde(int u,int v){ed[++cnt]=(Edge){v,head[u]},head[u]=cnt;}
inline void add(int u,int v){adde(u,v),adde(v,u);}
#define FORE(i,Now) for(REG int i=head[Now];i;i=ed[i].nxt)

int A[MAXN];

int Win[MAXN];

void dfs(int Now,int Fa){
int Min=1000000001;
FORE(i,Now){
int v=ed[i].v;
if(v==Fa) continue;
dfs(v,Now);
if(Win[v]) continue;
Min=A[v]<Min?A[v]:Min;
}
if(Min>=A[Now]) Win[Now]=0;
else Win[Now]=1;
}

inline void Work(){
read(n);
for(REG int i=1;i<=n;++i) read(A[i]);
for(REG int i=1;i<n;++i){int u,v;read(u),read(v),add(u,v);}
for(REG int i=1;i<=n;++i){
memset(Win,0,sizeof Win);
dfs(i,i);
if(Win[i]) printf("%d ",i);
}
}

int main(){Work();}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×