BZOJ 3164: [Heoi2013]Eden的博弈问题
3164: [Heoi2013]Eden的博弈问题
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 134 Solved: 98
[Submit][Status][Discuss]
Description
对于有两个玩家的,状态透明且状态转移确定的博弈游戏,博弈树是常用的分析工具。博弈树是一棵有根树,其中的节点为游戏的状态。若节点B的父亲是A,则说明状态A能通过一次决策转移到状态B。每个状态都有一个唯一的决策方,即这个状态下应该由哪一方做出决策。我们规定双方在任何时候都是轮流做出决策的,即树上相邻节点的决策方总是不相同的。在这个问题中,我们只关心两个玩家的胜负情况,且规定游戏不会出现平局。 我们称两个玩家分别为黑方和白方,其中根节点的决策方为黑方。显然每个节点 只有两个状态:黑方胜和白方胜。若某内节点(即存在后继节点的节点)的决策 方为黑方,则该节点为黑方胜的充要条件为它的儿子中存在黑方胜的节点,反之亦然。求解博弈树即为判明博弈树根节点的状态。如果我们得知了所有叶节点(即无后继节点的节点)的状态,那么博弈树就 很容易求解了。但是现在的情况是所有叶节点的状态均为未知的,需要进一步的计算。对于一个由叶节点构成的集合S,如果S中的节点均被判明为黑方胜,就可以断言根节点为黑方胜的话,则称 S为一个黑方胜集合。对于黑方胜集合 S,
如果对于任意的黑方胜集合 S’均满足|S| ≤ |S’ |(|S|表示集合S中的元素数目),
则称S为一个最小黑方胜集合。同样地,也可以定义白方胜集合和最小白方胜集合。
Eden最近在研究博弈树问题。他发现,如果一个叶节点既属于某一个最小黑方胜集合,又属于一个最小白方胜集合,那么求解这个节点的状态显然最有益 于求解根节点的状态。像这样的叶节点就称之为关键叶节点。对于一棵给定的博弈树,Eden想要知道哪些叶节点是关键叶节点。
Input
每个测试点包含一组测试数据。
测试数据的第一行包含一个正整数n,表示博弈树的节点数目。节点从1到n 编号,且 1 号节点为根节点。
之后n–1 行,每行包含一个正整数。第i行的正整数表示节点i的父节点的编号。
Output
在一行内输出三个空格分隔的正整数,分别是编号最小的关键叶节点的编号,
关键叶节点的数目和所有关键叶节点的编号的异或和。
Sample Input
1
1
2
2
3
3
Sample Output
4 4 0
HINT
对于100% 的数据,1 ≤ n ≤ 200,000 ,且对于节点 i(i ≠ 1 ),其父节点的编号小于i。
Source
这贪心好水啊~~~
1 #include <cstdio> 2 3 template <class T> 4 inline T min(const T &a, const T &b) 5 { 6 return a < b ? a : b; 7 } 8 9 const int mxn = 200005; 10 const int inf = 1000000007; 11 12 int n, fat[mxn]; 13 14 int hd[mxn]; 15 int to[mxn]; 16 int nt[mxn]; 17 18 inline void addEdge(int u, int v) 19 { 20 static int tot = 0; 21 nt[++tot] = hd[u]; 22 to[tot] = v; 23 hd[u] = tot; 24 } 25 26 int dep[mxn]; 27 28 void preDFS(int u, int d) 29 { 30 dep[u] = d; 31 32 for (int i = hd[u]; i; i = nt[i]) 33 preDFS(to[i], d ^ 1); 34 } 35 36 namespace tree1 37 { 38 int f[mxn]; 39 int v[mxn]; 40 41 void DFS1(int u) 42 { 43 if (!hd[u]) 44 f[u] = 1; 45 else 46 { 47 if (dep[u]) 48 { 49 f[u] = 0; 50 51 for (int i = hd[u]; i; i = nt[i]) 52 DFS1(to[i]), f[u] = f[u] + f[to[i]]; 53 } 54 else 55 { 56 f[u] = inf; 57 58 for (int i = hd[u]; i; i = nt[i]) 59 DFS1(to[i]), f[u] = min(f[u], f[to[i]]); 60 } 61 } 62 } 63 64 void DFS2(int u) 65 { 66 if (!hd[u]) 67 v[u] = 1; 68 else 69 { 70 if (dep[u]) 71 { 72 for (int i = hd[u]; i; i = nt[i]) 73 DFS2(to[i]); 74 } 75 else 76 { 77 for (int i = hd[u]; i; i = nt[i]) 78 if (f[to[i]] == f[u])DFS2(to[i]); 79 } 80 } 81 } 82 83 inline void solve(void) 84 { 85 DFS1(1); 86 DFS2(1); 87 } 88 } 89 90 namespace tree2 91 { 92 int f[mxn]; 93 int v[mxn]; 94 95 void DFS1(int u) 96 { 97 if (!hd[u]) 98 f[u] = 1; 99 else 100 { 101 if (!dep[u]) 102 { 103 f[u] = 0; 104 105 for (int i = hd[u]; i; i = nt[i]) 106 DFS1(to[i]), f[u] = f[u] + f[to[i]]; 107 } 108 else 109 { 110 f[u] = inf; 111 112 for (int i = hd[u]; i; i = nt[i]) 113 DFS1(to[i]), f[u] = min(f[u], f[to[i]]); 114 } 115 } 116 } 117 118 void DFS2(int u) 119 { 120 if (!hd[u]) 121 v[u] = 1; 122 else 123 { 124 if (!dep[u]) 125 { 126 for (int i = hd[u]; i; i = nt[i]) 127 DFS2(to[i]); 128 } 129 else 130 { 131 for (int i = hd[u]; i; i = nt[i]) 132 if (f[to[i]] == f[u])DFS2(to[i]); 133 } 134 } 135 } 136 137 inline void solve(void) 138 { 139 DFS1(1); 140 DFS2(1); 141 } 142 } 143 144 signed main(void) 145 { 146 scanf("%d", &n); 147 148 for (int i = 2; i <= n; ++i) 149 scanf("%d", fat + i); 150 151 for (int i = 2; i <= n; ++i) 152 addEdge(fat[i], i); 153 154 preDFS(1, 0); 155 156 tree1::solve(); 157 tree2::solve(); 158 159 int ans1 = inf, ans2 = 0, ans3 = 0; 160 161 for (int i = 1; i <= n; ++i) 162 if (tree1::v[i] && tree2::v[i]) 163 { 164 ans1 = min(ans1, i); 165 ans2 = ans2 + 1; 166 ans3 = ans3 ^ i; 167 } 168 169 printf("%d %d %d\n", ans1, ans2, ans3); 170 }
@Author: YouSiki