BZOJ 4169 LMC的游戏 (博弈+树dp)

博客讲述了如何解决一道关于博弈论和树形动态规划的编程题。题目涉及一个两人游戏,玩家在有根树上移动棋子,目标是通过最优策略最大化或最小化到达叶子节点的编号。通过定义状态F[i]表示在节点i能取得的最大叶子编号,博主分析了先手和后手的转移策略,并给出了问题的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4169 LMC的游戏

【题目描述】

RHL 有一天看到 lmc 在玩一个游戏。
“愚蠢的人类哟,what are you doing”,RHL 说。
“我在玩一个游戏。现在这里有一个有 n 个结点的有根树,其中有 m 个叶子结点。这 m个叶子从 1 到 m 分别被给予了一个号码,每个叶子的号码都是独一无二的。一开始根节点有一个棋子,两个玩家每次行动将棋子移动到当前节点的一个儿子节点。当棋子被移动到某个叶节点的时候游戏结束,这个叶节点的号码即为该局游戏的 result。先手的玩家要最大化result,后手的玩家要最小化这个 result。”
“你不先问一下我是谁吗 = =”
“那么,who are you”
“我是这个世界的创造者,维护者和毁灭者,整个宇宙的主宰,无所不知,无所不能的,三个字母都大写的 RHL。”
“既然你这么厉害,那你一定知道,在两个玩家都无限聪明的情况下,在树的形态已知的情况下,在叶子的编号可以任意安排的情况下,游戏的 result 最大是多少咯。”

【输入格式】

输入数据第一行有一个正整数 n,表示结点的数量。
接下来 n-1 行,每行有两个正整数 u 和 v,表示的父亲节点是 u。

【输出格式】

输出一行 2 个非负整数,分别表示 result 的最大值和最小值。

【样例输入】

5
1 2
1 3
2 4
2 5

【样例输出】

3 2

【样例解释】

有 3,4,5 三个叶子。若令 3 号叶子的编号是 3,则先手可以移到 3 号结点,故 result
最大是 3。若 3 号叶子的编号是 2,则先手可以移到 3 号结点,故 result 最小是 2.

【数据范围】

30%,n<=10
100%,n<=200000


有意思的博弈题。只考虑最大值的情况,最小值是类似的。
F[i]F[i]表示在ii号点能取得子树中第F[i]大的叶子。
如果ii号点是先手移动,那么F[i]=min(F[soni]),这个转移是显然的。
如果ii号点是后手移动,那么F[i]=F[soni],这个转移是因为后手肯定会选择第F[soni]F[soni]大的值最小的子树移动,因此最后取得的一定是第F[soni]∑F[soni]大的。

如果ii号点是叶子,那么F[i]=1


代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 200005
using namespace std;
int n,m,dp[2][N],rt;
int TOT,LA[N],NE[N],EN[N];
bool mark[N],mmark[N];
void ADD(int x,int y)
{
    TOT++;
    EN[TOT]=y;
    NE[TOT]=LA[x];
    LA[x]=TOT;
}
void DFS(int x,int ty)
{
    if(!mmark[x]){dp[0][x]=dp[1][x]=1;return;}
    dp[ty][x]=1e9;
    for(int i=LA[x];i;i=NE[i])
    {
        int  y=EN[i];DFS(y,ty^1);
        dp[ty][x]=min(dp[ty][x],dp[ty][y]);
        dp[ty^1][x]+=dp[ty^1][y];
    }
}
int main()
{
    int i,j,k,x,y;
    scanf("%d",&n);
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        mark[y]=1;
        mmark[x]=1;
        ADD(x,y);
    }
    for(i=1;i<=n;i++)if(!mark[i])rt=i;
    for(i=1;i<=n;i++)if(!mmark[i])m++;
    DFS(rt,0);
    printf("%d %d",m-dp[0][rt]+1,dp[1][rt]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值