HDU 4958/BC 5C Poor Rukaw

22 篇文章 0 订阅
5 篇文章 0 订阅

博弈+概率dp

题目大意:2个人玩游戏,其中甲随手玩。。。乙认真玩,开始n堆石子,每次拿2堆相减后放回去,最后剩奇数甲赢,否则乙赢。赢的得n分,下一轮n堆石子恢复,上轮输者删掉其中一堆,问最后乙得分的期望。

首先,由于是博弈,从必败态开始分析,对于甲来说,最后一次奇数是必胜的,而每次转移状态的操作,只有 拿出两个奇数 变成偶数,奇偶变奇,偶偶变偶三种,不管哪种,奇数数量是减少2个或0个,即每次操作只能减少偶数个奇数,所以如果开始有奇数个奇数,则甲必胜。这样对于n轮中的每一轮的判断就有了。

下面开始看2个人的擅长操作,因为甲随手玩,所以随机删除,而如果乙输了,乙删除,乙输了表示此事有奇数个奇数,由于越靠近前面的轮次分越高,所以乙肯想尽早赢,所以乙要删除一个奇数,使自己进入必胜态。所以可以递推,我用的记忆化搜索,跟dp差不多快,还好理解。递推公式的意义见注释

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include<stack>
#define inf 0x3f3f3f3f
#define ll long long
#define mod 1000000007
using namespace std;
#define bug puts("bugbugubgbugbug");
double ans;
double visit[1005][1005];
double dfs(int ji,int ou)
{
    if(ji+ou<=0)return 0;
    if(visit[ji][ou])return visit[ji][ou];//不记忆化搜索会t掉
    if(ji%2==1)
        return visit[ji][ou]=dfs(ji-1,ou);//如果乙输了,直接删奇数,进入下一个状态
    if(ji)//甲输了,这时随机删一个数
    {
        if(ou)//奇偶都存在是,按比例推出状态 例 取奇数概率为 ji/ji+ou 取奇数状态为dfs(ji-1,ou)
            return visit[ji][ou]=(dfs(ji-1,ou)*ji+dfs(ji,ou-1)*ou)/(ji+ou)+ji+ou;
        else//只剩奇数
            return visit[ji][ou]=dfs(ji-1,ou)+ji+ou;
    }
    return visit[ji][ou]=dfs(ji,ou-1)+ji+ou;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(visit,0,sizeof(visit));
        ans=0;
        int n;
        scanf("%d",&n);
        int ji=0,ou=0;
        for(int i=0; i<n; i++)
        {
            int a;
            scanf("%d",&a);
            if(a%2)ji++;
            else ou++;
        }
        ans=dfs(ji,ou);
        printf("%d\n",(int)(3*ans+0.5));


    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值