D. Iris and Game on the Tree
Iris 有一棵树,其根节点为 1 1 1 。每个顶点的值为 0 \mathtt 0 0 或 1 \mathtt 1 1 。
让我们考虑树的一片叶子(顶点 1 1 1 永远不会被视为叶子)并定义其权重。构造一个由从根节点开始到该叶子节点结束的路径上顶点的值组成的字符串。然后,叶子节点的权重是其中子字符串 10 \mathtt{10} 10 和 01 \mathtt{01} 01 的出现次数之差。
以下面的树为例。绿色顶点的值为 1 \mathtt 1 1 ,而白色顶点的值为 0 \mathtt 0 0 。
- 让我们计算叶子节点 5 5 5 的权重:形成的字符串为 10110 \mathtt{10110} 10110 。子字符串 10 \mathtt{10} 10 的出现次数为 2 2 2 ,子字符串 01 \mathtt{01} 01 的出现次数为 1 1 1 ,因此差值为 2 − 1 = 1 2 - 1 = 1 2−1=1 。
- 让我们计算叶子节点 6 6 6 的权重:形成的字符串为 101 \mathtt{101} 101 。子字符串 10 \mathtt{10} 10 的出现次数为 1 1 1 ,子字符串 01 \mathtt{01} 01 的出现次数为 1 1 1 ,因此差值为 1 − 1 = 0 1 - 1 = 0 1−1=0 。
树的得分定义为树中权重非零的叶子的数量。
但有些顶点的值尚未确定,将以 ? \texttt{?} ? 的形式提供给您。填空太无聊了,所以 Iris 打算邀请 Dora 玩游戏。每次轮到一位女孩选择剩余值为 ? \texttt{?} ? 的顶点之一,并将其值更改为 0 \mathtt{0} 0 或 1 \mathtt{1} 1 ,Iris 先走。游戏持续进行,直到树中没有剩余值为 ? \mathtt{?} ? 的顶点。Iris 的目标是最大化树的得分,而 Dora 的目标是最小化得分。
假设两个女孩都发挥出最佳水平,请确定树的最终得分。
思路:
很容易想到,一条从根到叶子的路径是否有得分,只取决于根节点与叶子节点是否相同。相同则无贡献,不同则有贡献。
那么双方博弈就很简单了,只用看根节点和叶子的情况,先手抢占有利的一方即可。
只有一种特殊情况下需要考虑到路径节点上的’?‘,即当根节点为‘?’,且叶子节点中‘0’、‘1’的数量相等时(也可以都为0),此时双方处于平衡状态,在根节点和叶子节点上先手的一方反而会成为后手,所以Iris需要利用中间路径上的‘?’来拉扯一下,如果中间路径上的’?'数量为奇数,那么通过拉扯就可以使先后手转换,那么Iris就不会亏掉这一分。
代码:
#include <bits/stdc++.h>
#define endl '\n'
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
typedef long long ll;
using namespace std;
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<vector<int>> g(n + 1);
for (int i = 1; i < n; ++i) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
string s;
cin >> s;
int zeros = 0, ones = 0, ques = 0;
int allq = std::count(s.begin(), s.end(), '?'); // 统计输入字符串中?的数量
// cout<<"allq="<<allq<<endl;
// 遍历所有节点,统计叶子节点值和?的数量
for (int i = 2; i <= n; ++i) {
if (g[i].size() == 1) { // 如果节点是叶子
if (s[i - 1] == '0') {
zeros++;
} else if (s[i - 1] == '1') {
ones++;
} else {
ques++;
}
}
}
// cout<<"ques="<<ques<<endl;
int ans = 0;
// 根据根节点的值决定初始的ans
if (s[0] == '0') {
ans = ones; // 如果根是0,则非0的叶子数即为得分
} else if (s[0] == '1') {
ans = zeros; // 如果根是1,则非1的叶子数即为得分
} else { // 根节点是?
ans = max(zeros, ones); // 取较多的那个,因为根会变成较多的那个
if (ones == zeros && (allq - ques - 1) % 2 == 1 && (allq - ques - 1) > 0) {
// cout<<allq - ques - 1<<" ok"<<endl;
ques++;
}
ques--;
}
ans += (ques + 1) / 2;
// cout << ques << " ";
cout << ans << '\n';
}
return 0;
}