12. Game on Tree 3

题目链接:Game on Tree 3

有一棵含有 n n n 个节点的树,节点编号从 1 1 1 n n n,根节点为 1 1 1,所有非根节点均有一个正整数权值。根节点上放有一个棋子。T 和 A 两个人正在玩一个回合制游戏。一个回合中:

  • A 先选取一个非根节点,将其权值变为 0 0 0
  • 然后 T 将棋子移动到当前位置的任意一个儿子上
  • 若棋子位于叶子节点,游戏结束;T 也可以在此时强行结束游戏

游戏结束时 T 会获得棋子所在位置的权值的得分。T 想最大化得分,而 A 想最小化得分,问两人在最优策略下 T 最后的得分是多少。

先看官方题解:

由于验证 T 能否至少得到 x x x 分比较容易,我们可以二分他的得分。假设当前 check 的是至少得到 x x x 分的情况,则将树上权值小于 x x x 的节点染成白色,权值大于等于 x x x 的节点染成黑色,然后进行树形 dp:设 d p [ u ] dp[u] dp[u] 表示在以 u u u 为根节点的子树中 A 需要额外染色 d p [ u ] dp[u] dp[u] 次才能使 T 无法走到黑色节点。那么状态转移方程:

d p [ u ] = max ⁡ ( ∑ d p [ v ] − 1 , 0 ) + [ v a l u ≥ x ] dp[u]=\max(\sum dp[v]-1,0)+[val_u\ge x] dp[u]=max(dp[v]1,0)+[valux]

其中 v v v u u u 的子节点。求和后减一是因为在 T 走下去之前还有一次变颜色的机会。

最后如果 d p [ 1 ] > 0 dp[1]\gt 0 dp[1]>0 说明可以取到大于等于 x x x 的权值。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 2e5 + 5;
vector<int> g[maxn];
int a[maxn], dp[maxn];
void dfs(int u, int f, int x) {
    dp[u] = 0;
    for (auto v : g[u]) {
        if (v == f)
            continue;
        dfs(v, u, x);
        dp[u] += dp[v];
    }
    dp[u] = max(dp[u] - 1, 0) + (a[u] >= x);
}
void solve() {
    int n;
    cin >> n;
    for (int i = 2; i <= n; ++i) {
        cin >> a[i];
    }
    for (int i = 1, u, v; i < n; ++i) {
        cin >> u >> v;
        g[u].push_back(v), g[v].push_back(u);
    }
    int l = 0, r = 1e9, ans = 0;
    while (l <= r) {
        int mid = (l + r) >> 1;
        dfs(1, 0, mid);
        if (dp[1] > 0)
            l = mid + 1, ans = mid;
        else
            r = mid - 1;
    }
    cout << ans << endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
}

这种染色的技巧在一些数据结构题中也有出现,在不太容易直接计算但比较容易 check 的情况下可以尝试一下。

那么能不能直接求出这个答案呢?我的室友给出了一种更为巧妙的做法:

先考虑树的高度是 1 1 1 的情况,显然 A A A 的最优选择是改变权值最大的那个叶子节点。

如果上面的这个东西是一个子树,那么它就会向父亲的地方输送除去这个权值之外的所有权值。然后又会产生一个改变权值的机会,所以就从这些权值里再删掉一个最大的。这个过程可以用可并堆来维护。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 2e5 + 5;
const ll mod = 998244353;
vector<int> g[maxn];
int a[maxn];
int fa[maxn], ls[maxn], rs[maxn], d[maxn];
int findfa(int x) { 
    return fa[x] == x ? fa[x] : (fa[x] = findfa(fa[x]));
}
int merge(int x, int y) {
    if (!x || !y) {
        d[x] = d[y] = 0;
        return x + y;
    }
    if (a[x] < a[y]) 
        swap(x, y);
    rs[x] = merge(rs[x], y);
    if (d[ls[x]] < d[rs[x]])
        swap(ls[x], rs[x]);
    d[x] = d[rs[x]] + 1;
    return x;
}
int join(int x, int y) {
    x = findfa(x), y = findfa(y);
    if (x == y) 
        return x;
    fa[x] = fa[y] = merge(x, y);
    return fa[x];
}
int pop(int x) {
    x = findfa(x);
    int t = x, y = rs[x];
    x = ls[x];
    fa[x] = fa[y] = fa[t] = merge(x, y);
    return fa[x];
}
int dfs(int u, int f) {
    if (u != 1 && g[u].size() == 1)
        return u;
    int rt = 0;
    for (auto v: g[u]) {
        if (v == f)
            continue;
        int r = dfs(v, u);
        if (!rt)
            rt = r;
        else 
            rt = join(rt, r);
    }
    rt = pop(rt);
    return join(rt, u);
}
void solve() {
    int n;
    cin >> n;
    for (int i = 2; i <= n; ++i) {
        cin >> a[i];
    }
    for (int i = 1; i <= n; ++i) {
        fa[i] = i;
    }
    for (int i = 1, u, v; i < n; ++i) {
        cin >> u >> v;
        g[u].push_back(v), g[v].push_back(u);
    }
    int ans = dfs(1, 0);
    cout << a[ans] << endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个很有趣的小项目,使用Python的GUI库Tkinter可以实现这个游戏。以下是游戏的大致流程: 1. 创建一个游戏开始界面,包括一个开始按钮。 2. 当用户点击开始按钮时,打开一个新窗口,显示三种不同款式的树身供用户选择,并实时显示用户选择的树身效果。 3. 用户选择树身后,点击继续按钮,打开一个新窗口,显示三种不同的装饰物(雪花、糖果、彩带),可任意组合,并实时显示用户选择的装饰效果。 4. 用户选择装饰后,点击继续按钮,打开一个新窗口,显示三个不同的祝福语供用户选择,并实时显示用户选择的祝福语效果。 5. 用户选择祝福语后,点击确定按钮,生成最终效果并显示在一个新窗口中。用户可以保存图片或重玩游戏。 以下是一个简单的实现代码: ```python import tkinter as tk from PIL import ImageTk, Image class ChristmasTreeGame: def __init__(self, master): self.master = master self.master.title("圣诞树游戏") self.master.geometry("500x500") self.start_button = tk.Button(self.master, text="开始游戏", command=self.start_game) self.start_button.pack(pady=50) def start_game(self): self.start_button.destroy() self.show_tree_style() def show_tree_style(self): self.tree_style = tk.StringVar() self.tree_style.set("tree1") tree1_image = ImageTk.PhotoImage(Image.open("tree1.png")) tree2_image = ImageTk.PhotoImage(Image.open("tree2.png")) tree3_image = ImageTk.PhotoImage(Image.open("tree3.png")) tree1_button = tk.Radiobutton(self.master, image=tree1_image, variable=self.tree_style, value="tree1") tree2_button = tk.Radiobutton(self.master, image=tree2_image, variable=self.tree_style, value="tree2") tree3_button = tk.Radiobutton(self.master, image=tree3_image, variable=self.tree_style, value="tree3") tree1_button.image = tree1_image tree2_button.image = tree2_image tree3_button.image = tree3_image tree1_button.pack(pady=50) tree2_button.pack(pady=50) tree3_button.pack(pady=50) continue_button = tk.Button(self.master, text="继续", command=self.show_decorations) continue_button.pack(pady=20) def show_decorations(self): self.decorations = [] decoration_images = [] decoration_images.append(ImageTk.PhotoImage(Image.open("snowflake.png"))) decoration_images.append(ImageTk.PhotoImage(Image.open("candy.png"))) decoration_images.append(ImageTk.PhotoImage(Image.open("ribbon.png"))) snowflake_button = tk.Checkbutton(self.master, image=decoration_images[0], variable=self.decorations, onvalue="snowflake") candy_button = tk.Checkbutton(self.master, image=decoration_images[1], variable=self.decorations, onvalue="candy") ribbon_button = tk.Checkbutton(self.master, image=decoration_images[2], variable=self.decorations, onvalue="ribbon") snowflake_button.image = decoration_images[0] candy_button.image = decoration_images[1] ribbon_button.image = decoration_images[2] snowflake_button.pack(pady=50) candy_button.pack(pady=50) ribbon_button.pack(pady=50) continue_button = tk.Button(self.master, text="继续", command=self.show_greetings) continue_button.pack(pady=20) def show_greetings(self): self.greetings = tk.StringVar() self.greetings.set("Merry Christmas!") greeting1_button = tk.Radiobutton(self.master, text="Merry Christmas!", variable=self.greetings, value="Merry Christmas!") greeting2_button = tk.Radiobutton(self.master, text="Happy Holidays!", variable=self.greetings, value="Happy Holidays!") greeting3_button = tk.Radiobutton(self.master, text="Season's Greetings!", variable=self.greetings, value="Season's Greetings!") greeting1_button.pack(pady=50) greeting2_button.pack(pady=50) greeting3_button.pack(pady=50) confirm_button = tk.Button(self.master, text="确定", command=self.show_final_tree) confirm_button.pack(pady=20) def show_final_tree(self): final_tree_image = Image.open(self.tree_style.get() + ".png") for decoration in self.decorations: decoration_image = Image.open(decoration + ".png") final_tree_image.paste(decoration_image, (0, 0), decoration_image) final_tree_image = final_tree_image.resize((300, 300)) final_tree_image.save("final_tree.png") final_tree_tkimage = ImageTk.PhotoImage(final_tree_image) final_tree_label = tk.Label(self.master, image=final_tree_tkimage) final_tree_label.image = final_tree_tkimage final_tree_label.pack(pady=50) if __name__ == "__main__": root = tk.Tk() game = ChristmasTreeGame(root) root.mainloop() ``` 这个代码使用了Tkinter和Pillow库。在运行代码之前,确保在同一文件夹中有以下图片文件:tree1.png、tree2.png、tree3.png、snowflake.png、candy.png、ribbon.png。 这个游戏实现了上述流程,并在最后生成了一个最终效果的图片。你可以根据需要添加更多功能和优化。希望这能帮到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值