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 }