Codeforces 538E Demiurges Play Again(博弈DP)

http://codeforces.com/problemset/problem/538/E

题目大意:

给出一棵树,叶子节点上都有一个值,从1-m。有两个人交替从根选择道路,先手希望到达的叶子节点尽量大,后手希望到达的叶子节点尽量小,叶子节点的放置方案任意。两个人都足够聪明,能够得到的最大值和最小值分别是多少。

思路:

先考虑最大的情况

考虑dp[i]代表i这个节点能达到的最大的数字在这个子树中排第几。

如果当前是先手操作,那么他肯定会往最大的那个子树的方向走,即dp[u]=min(dp[v])

如果当前是后手操作,那么他肯定往最小的走,即dp[u]=Σdp[v],这样就走到了最差子树的最大数字去了。

然后最小的情况类似

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<iostream>
 6 int tot,go[400005],next[400005],first[200005];
 7 int n,f1[400005],f2[400005],pd[400005],son[400005],deep[400005];
 8 int read(){
 9     int t=0,f=1;char ch=getchar();
10     while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();}
11     while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();}
12     return t*f;
13 }
14 void insert(int x,int y){
15     tot++;
16     go[tot]=y;
17     next[tot]=first[x];
18     first[x]=tot;
19 }
20 void add(int x,int y){
21     insert(x,y);
22     insert(y,x);
23 }
24 void dfs(int x,int fa){
25     int pdd=0;
26     for (int i=first[x];i;i=next[i]){
27         int pur=go[i];
28         if (pur==fa) continue;
29         pdd=1;
30         deep[pur]=deep[x]+1;
31         dfs(pur,x);
32         son[x]+=son[pur];
33     }
34     if (!pdd) son[x]=1,pd[x]=1;
35 }
36 void dfs1(int x,int fa){
37     if (pd[x]==1) {
38         f1[x]=1;
39         return;
40     }
41     if (deep[x]%2){
42      f1[x]=0x7fffffff;
43      for (int i=first[x];i;i=next[i]){
44          int pur=go[i];
45          if (pur==fa) continue;
46          dfs1(pur,x);
47          f1[x]=std::min(f1[x],f1[pur]);
48      }
49     }else{
50      f1[x]=0;
51      for (int i=first[x];i;i=next[i]){
52          int pur=go[i];
53          if (pur==fa) continue;
54          dfs1(pur,x);
55          f1[x]+=f1[pur];
56      }
57     }
58 }
59 void dfs2(int x,int fa){
60     if (pd[x]==1) {
61         f2[x]=1;
62         return;
63     }
64     if (deep[x]%2){
65      f2[x]=0;
66      for (int i=first[x];i;i=next[i]){
67          int pur=go[i];
68          if (pur==fa) continue;
69          dfs2(pur,x);
70          f2[x]+=f2[pur];
71      }
72     }else{
73      f2[x]=0x7fffffff;
74      for (int i=first[x];i;i=next[i]){
75          int pur=go[i];
76          if (pur==fa) continue;
77          dfs2(pur,x);
78          f2[x]=std::min(f2[x],f2[pur]);
79      }
80     }
81 }
82 int main(){
83     n=read();
84     for (int i=1;i<n;i++){
85         int x=read(),y=read();
86         add(x,y);
87     }
88     deep[1]=1;
89     dfs(1,0);
90     dfs1(1,0);
91     printf("%d ",son[1]-f1[1]+1);
92     dfs2(1,0);
93     printf("%d\n",f2[1]);
94     return 0;
95 }
时间: 2024-10-27 19:40:56

Codeforces 538E Demiurges Play Again(博弈DP)的相关文章

CodeForces 540D Bad Luck Island 概率dp

CodeForces 540D 应该是简单概率dp,由于写得少显得十分蠢萌 求期望逆推,求概率正推,大概是这么个意思,贴一发留恋 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define db double const int maxn=108; db dp[maxn][maxn][maxn]; int main() { int i,j,n,m,k,p; whi

codeforces 148E Aragorn&#39;s Story 背包DP

Aragorn's Story Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/148/E Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who

UVA 1558 - Number Game(博弈dp)

UVA 1558 - Number Game 题目链接 题意:20之内的数字,每次可以选一个数字,然后它的倍数,还有其他已选数的倍数组合的数都不能再选,谁先不能选数谁就输了,问赢的方法 思路:利用dp记忆化去求解,要输出方案就枚举第一步即可,状态转移过程中,选中一个数字,相应的变化写成一个函数,然后就是普通的博弈问题了,必胜态之后必有必败态,必败态之后全是必胜态 代码: #include <stdio.h> #include <string.h> const int N = 105

CodeForces 21D Traveling Graph 状压dp+欧拉回路

题目链接:点击打开链接 题意: 给定n个点m条边的无向图 求从1点开始经过每条边至少一次最后回到1点的最小路程 显然就是找一条路径可重复的欧拉回路 思路: 首先对于欧拉回路的结论是:所有点的度数都为偶数 因为所有边至少经过一次,那么可以把题意转换成加最少多少条边使得图满足以上结论 而加的边目的是为了把奇度数转成偶度数,先floyd一下得到任意点间加边的最小花费 dp[i]表示状态i下度数都为偶数的最小花费. 状压dp,把i状态下,所有未选择的点中挑2个奇度数的转移即可. #include <cs

UVA 1557 - Calendar Game(博弈dp)

UVA 1557 - Calendar Game 题目链接 题意:给定一个日期,两个人轮流走,每次可以走一月或者一天,问最后谁能走到2001.11.4这个日子 思路:记忆化搜索,对于每个日期,如果下两个状态有一个非必胜态,那么这个状态是必胜态,如果后继状态都是必胜态,那么该状态为必败态 代码: #include <stdio.h> #include <string.h> const int day[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31,

UVA 1559 - Nim(博弈dp)

UVA 1559 - Nim 题目链接 题意:一开始有s个石子,2n个人轮流取石子,每个人有个最大能取数目,2n个人奇数一队,偶数一队,取到最后一个石子的队输,问谁赢 思路:记忆化搜索,每个人取的时候对应的后继状态如果有一个必败态,则该状态为必胜态,如果都是必胜态,则该状态为必败态 代码: #include <stdio.h> #include <string.h> int n, s, m[25], dp[25][10005]; int dfs(int now, int state

Codeforces 67C Sequence of Balls 编辑距离 dp

题目链接:点击打开链接 有一个交换操作比较特殊,所以记录每个点距离自己最近的那个字符的位置 然后交换就相当于把第一行要交换的2个字符 之间的字符都删掉 把第二行要交换的2个字符 之间的字符都插入第一行的2个字符之间 然后再进行交换. #include <cstdio> #include <cstring> #include<iostream> using namespace std; #define inf 10000000 #define N 4005 #define

Codeforces Round #261 (Div. 2) E (DP)

E. Pashmak and Graph Pashmak's homework is a problem about graphs. Although he always tries to do his homework completely, he can't solve this problem. As you know, he's really weak at graph theory; so try to help him in solving the problem. You are

Codeforces 15C Industrial Nim 简单博弈

题目链接:点击打开链接 题意: 给定n 下面n行,每行2个数u v 表示有v堆石子:u,u+1,u+2···u+v-1 问先手必胜还是后手必胜 思路: 首先根据Nim的博弈结论 把所有数都异或一下,看结果是0还是非0 而这里因为数字太多所以想优化 那么其实对于一个序列 u, u+1, u+2 ···· 显然 {4,5} {,6,7}, {8,9} 这样2个一组的异或结果就是1 那么只需要把序列分组,分成{偶数,奇数} 然后Y一下.. #include<stdio.h> #include<