AtCoder Grant Contest 10.F 博弈

题意:给定一棵树,每个节点有个权值,Alice和Bob轮流进行操作,给定游戏起点指针指向节点C。不断进行下述操作。

1.将当前节点权值-1,然后将指针从该节点移动到相邻节点,出现一方不能移动(即指针指向的节点权值为0)即为输。

思路:

两个性质:

1.先手只会往权值严格小于当前节点的地方走。不然对手只需要把棋子位置移回来就可以耗死对方。

2.若存在权值严格小的相邻节点i且sg[i]=0,则当前节点是必胜位置。

之后的细节就很好想啦~~

 

 1 #include"bits/stdc++.h"
 2 #define ci(x) scanf("%d",&x)
 3 #define cd(x) scanf("%lf",&x)
 4 #define cl(x) scanf("%lld",&x)
 5 #define pi(x) printf("%d\n",x)
 6 #define pd(x) printf("%f\n",x)
 7 #define pl(x) printf("%lld\n",x)
 8 using namespace std;
 9 const int N = 3e3 + 5;
10 int n;
11 int a[N];
12 vector<int> e[N];
13 int dfs(int u,int pre){
14     for(int i=0;i<e[u].size();i++){
15         int v=e[u][i];
16         if(v==pre) continue;
17         if(a[u]>a[v]&&!dfs(v,u)) return 1;//v为必败态点且权值小于u,u即为必胜态。
18     }
19     return 0;//必败态
20 }
21 int main() {
22     ci(n);
23     for(int i=1;i<=n;i++) ci(a[i]);
24     for(int i=1;i<=n;i++) e[i].clear();
25     for(int i=1;i<n;i++){
26         int x,y;
27         ci(x),ci(y);
28         e[x].push_back(y);
29         e[y].push_back(x);
30     }
31     for(int i=1;i<=n;i++) if(dfs(i,0)) printf("%d ",i);
32     puts("");
33     return 0;
34 }

 

posted @ 2018-09-14 21:55  thges  阅读(195)  评论(0编辑  收藏  举报