upc - 5212: Coins I(概率DP)

本文介绍了一个使用概率动态规划(DP)解决硬币翻转问题的方法,旨在通过有限次操作最大化硬币正面朝上的期望数量。文章详细解释了问题背景、策略选择以及递推式的推导过程。

题目描述

Alice and Bob are playing a simple game. They line up a row of n identical coins, all with the heads facing down onto the table and the tails upward.
For exactly m times they select any k of the coins and toss them into the air, replacing each of them either heads-up or heads-down with the same possibility. Their purpose is to gain as many coins heads-up as they can.

输入

The input has several test cases and the first line contains the integer t (1 ≤ t ≤ 1000) which is the total number of cases.
For each case, a line contains three space-separated integers n, m (1 ≤ n, m ≤ 100) and k (1 ≤ k ≤ n).

输出

For each test case, output the expected number of coins heads-up which you could have at the end under the optimal strategy, as a real number with the precision of 3 digits.

样例输入

6
2 1 1
2 3 1
5 4 3
6 2 3
6 100 1
6 100 2

样例输出

0.500
1.250
3.479
3.000
5.500
5.000

来源/分类

ICPC2017  Urumqi 

 

原来还有概率dp这种东西.......

题意:

给出n个反着的硬币,m次操作,每次可以任选k个硬币抛向空中,每个落下来  正反的概率各占一半。

问,在尽量使硬币为正的策略下,最后的正面期望值。

 

分析:

想了很久的规律....丝毫没有考虑到dp...

首先,最优策略就是:每次选取k个的时候,我们先选反面朝上的硬币,如果不够,再选正面朝上的

因为每次的翻转只跟上次的翻转情况有关,所以我们可以推导一下递推式dp

很容易想到dp[i][j] 表示 翻转完第i次时,j个硬币正面朝上的概率

 

递推式:我们得到了dp[i][j] 第 i 次翻转后有 j 个正面朝上,这时候我们进行第 i+1 次翻转,会遇到两种情况:

  1. j+k<=n: 即我们可以选k个反面朝上的硬币操作,然后可以求得这k个硬币中朝上的个数 t 的概率p,那么dp[i+1][j+t] = dp[i][j]*p;    p = C(k,t)* (1/2)^k
  2. j+k > n: 即需要选择 tp=(j+k-n) 个正面朝上的硬币进行翻转,所以第i+1次翻转后确定的正面朝上的个数为 j-tp 个,然后考虑k个刚翻转的正面朝上的个数t 的概率p,p还是C(k,t)* (1/2)^k;所以此时递推式为 dp[i+1][j-tp+t] = dp[i][j]*p;

而且:对于给定的k,t 的概率p恒为 C(k,t)* (1/2)^k,所以可以先预处理这一部分

AC代码:

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3fLL
#define pi acos(-1.0)
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
ll qpow(ll x, ll y, ll mod){ll s=1;while(y){if(y&1)s=s*x%mod;x=x*x%mod;y>>=1;}return s;}

int n, m, k;
double dp[105][105];
double C[105][105], p[105];

void init()
{
    C[0][0] = 1; p[0] = 1;
    for(int i=1;i<105;i++)
    {
        C[i][0]=1;
        p[i]=p[i-1]*0.5;
        for(int j=1;j<=i;j++)
            C[i][j]=C[i-1][j]+C[i-1][j-1];
    }
    for(int i=0;i<=k;i++) C[k][i]*=p[k];
}
int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d%d", &n, &m, &k);
        init(); ms(dp, 0);
        dp[0][0] = 1;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<=n;j++)
            {
                if(j+k<=n)
                {
                    for(int t=0;t<=k;t++)
                        dp[i+1][j+t] += dp[i][j]*C[k][t];
                }
                else
                {
                    int tp=j+k-n;
                    for(int t=0;t<=k;t++)
                        dp[i+1][j+t-tp] += dp[i][j]*C[k][t];
                }
            }
        }
        double ans = 0;
        for(int i=1; i<=n; i++)
            ans += i*dp[m][i];

        printf("%.3f\n", ans);
    }

    return 0;
}

 

<template> <div class="vipDetil"> <!-- 返回图标 --> <div class="icon" v-if="isRevert"> <van-icon name="arrow-left" size="30" @click="revert" /> <div></div> </div> <!-- 功能列表 --> <div class="" style="padding: 185px 10px 10px;height: 90vh;overflow: hidden auto;"> <div style="margin-bottom: 10px;padding: 10px;background-color: #fff;border-radius: 10px;" v-for="(item, index) in list" :key="index"> <div style="display: flex;flex-direction: row;justify-content: space-between;color: #fc642d;padding: 0px 5px;"> <div style="display: flex;flex-direction: row;align-items: baseline;"> <div style="font-size: 28px;font-weight: 400;font-family: YouSheBiaoTiHei;">{{ item.name }} </div> </div> <div style="display: flex;flex-direction: row;align-items: baseline;"> <div style="font-size: 12px;font-weight: 600;">¥</div> <div style="font-size: 30px;font-weight: 600;">{{ item.prize }}</div> </div> </div> <div style="font-size: 14px;padding: 0px 5px 10px;color: #fc642d;">{{ item.miniTitle }}</div> <div style="display: flex;flex-direction: row;justify-content: space-between;align-items: baseline;background-color: #FFF7DF;padding: 5px 15px 5px 5px;border-radius: 10px;"> <div> <div style="display: flex;flex-direction: row;"> <div style="text-align: center;"> <img :src="item.coins.icon" alt="" style="width: 50px;height: 50px;"> <div style="font-size: 10px;">{{ item.coins.amount }}平台币</div> </div> <div style="text-align: center;margin: 0px 20px;"> <img :src="item.points.icon" alt="" style="width: 50px;height: 50px;"> <div style="font-size: 10px;">{{ item.points.amount }}积分</div> </div> <div style="text-align: center;"> <img :src="item.couponResp.icon" alt="" style="width: 50px;height: 50px;"> <div style="font-size: 10px;">满{{ item.couponResp.limitAmount }}减{{ item.couponResp.amount }}折扣券</div> </div> </div> </div> <div style="text-align: center;padding-top: 10px;"> <div style="padding: 5px 25px;font-size: 14px;background-color: #fc642d;color: #fff;border-radius: 20px;"> 购买 </div> <div style="font-size: 10px;color: #AD6200;margin-top: 2px;">限购<span style="font-size: 10px;">{{ item.buyedTimes }}/{{ item.buyTimes }}</span></div> </div> </div> </div> </div> <!-- 规则图标 --> <div class="bb"> <span></span> </div> </div> </template> <script setup> import { useRouter } from "vue-router"; import { ref, onMounted } from "vue"; import { getCelebrationList } from "@/api/home.js"; import { isWechat, isInStandaloneMode } from "@/utils/tool"; const router = useRouter(); const isRevert = ref(false); const list = ref([]); onMounted(() => { if (localStorage.getItem("userTokens") == null) { window.location.href = '/H5/homeOpen'; } if (isWechat()) { isRevert.value = false; } else { if (isInStandaloneMode()) { isRevert.value = true; } else { isRevert.value = false; } } getList(); }); const getList = async () => { const res = await getCelebrationList({ userId: localStorage.getItem("userIds"), userToken: localStorage.getItem("userTokens"), }); if (res.status == 200) { console.log(res.data, '没错,是我'); list.value = res.data; } }; const revert = () => { router.go(-1); } </script> <style lang="less" scoped> .vipDetil { width: 100%; box-sizing: border-box; position: relative; height: 100vh; background-image: url(../assets/images/one_bg.png); /* 使用绝对路径 */ background-size: cover; /* 背景图片覆盖整个容器 */ background-repeat: no-repeat; /* 背景图片不重复 */ background-position: center; /* 背景图片居中 */ } .icon { display: flex; flex-direction: row; justify-content: space-between; align-items: center; margin-bottom: 10px; padding: 10px 0px; } .bb { position: absolute; top: 15vh; right: 14%; width: 24px; height: 24px; background-image: url(../assets/images/one_gz.png); background-size: cover; background-repeat: no-repeat; background-position: center; } </style>监听列表的滚动当滚动大于100px时,让规则图标消失,滚动回去时,显示规则图标。
最新发布
09-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值