概率 DP 例题

1、

Island of Survival

You are in a reality show, and the show is way too real that they threw into an island. Only two kinds of animals are in the island, the tigers and the deer. Though unfortunate but the truth is that, each day exactly two animals meet each other. So, the outcomes are one of the following

a)      If you and a tiger meet, the tiger will surely kill you.

b)      If a tiger and a deer meet, the tiger will eat the deer.

c)      If two deer meet, nothing happens.

d)      If you meet a deer, you may or may not kill the deer (depends on you).

e)      If two tigers meet, they will fight each other till death. So, both will be killed.

If in some day you are sure that you will not be killed, you leave the island immediately and thus win the reality show. And you can assume that two animals in each day are chosen uniformly at random from the set of living creatures in the island (including you).

Now you want to find the expected probability of you winning the game. Since in outcome (d), you can make your own decision, you want to maximize the probability.

Input

Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case starts with a line containing two integers t (0 ≤ t ≤ 1000) and d (0 ≤ d ≤ 1000) where t denotes the number of tigers and d denotes the number of deer.

Output

For each case, print the case number and the expected probability. Errors less than 10-6 will be ignored.

Sample Input

4

0 0

1 7

2 0

0 10

Sample Output

Case 1: 1

Case 2: 0

Case 3: 0.3333333333

Case 4: 1

题意:

  1. 如果你和老虎相遇,老虎肯定会杀了你
  2. 如果老虎和鹿相遇,老虎就会吃掉鹿
  3. 如果两只鹿相遇,什么也不会发生
  4. 如果你遇到鹿,你可能会或可能不会杀死鹿(取决于你)
  5. 如果两个老虎相遇,他们会互相争斗,直到死亡。所以,两者都将被杀死。

现在让你求你预期存活的期望值:

人的生死只有老虎存不存在有关,所以可以将鹿给忽略(鹿要不会被老虎吃掉,要么被人杀死,与人的存活率无关)

分析老虎的数量

1、如果老虎是 0 只,那么人的存活率是 1

2、如果老虎是奇数的话,两只老虎见面最终会被杀死,那么总会剩余一只,那么人的存活率是 0

3、分析老虎的数量是偶数的情况:(人存活的话就让两只老虎互相残杀好啦)

      人存活的概率是就是两只老虎互相残杀的概率

    那么你存活的概率是:

Code:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#include<stack>
#define LL long long
using namespace std;
int main()
{
    int t;
    int n,m;
    int flag=1;
    cin>>t;
    while(t--)
    {
        double ans=1;
        scanf("%d %d",&n,&m);
        if(n==0){
            printf("Case %d: ",flag++);
            printf("1\n");
        }
        else{
            if(n%2!=0){
                printf("Case %d: ",flag++);
                printf("0\n");
            }
            else
            {
                while(n)
                {
                    ans*=(double)(n-1)/(n+1); 
                    n-=2;   // 每次减少两只老虎
                }
                printf("Case %d: %.10f\n",flag++,ans);
            }
        }
    }
}

 

2、D - Dice (III)

Given a dice with n sides, you have to find the expected number of times you have to throw that dice to see all its faces at least once. Assume that the dice is fair, that means when you throw the dice, the probability of occurring any face is equal.

For example, for a fair two sided coin, the result is 3. Because when you first throw the coin, you will definitely see a new face. If you throw the coin again, the chance of getting the opposite side is 0.5, and the chance of getting the same side is 0.5. So, the result is

1 + (1 + 0.5 * (1 + 0.5 * ...))

= 2 + 0.5 + 0.52 + 0.53 + ...

= 2 + 1 = 3

Input

Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 105).

Output

For each case, print the case number and the expected number of times you have to throw the dice to see all its faces at least once. Errors less than 10-6 will be ignored.

Sample Input

5

1

2

3

6

100

Sample Output

Case 1: 1

Case 2: 3

Case 3: 5.5

Case 4: 14.7

Case 5: 518.7377517640

 

题意:

一个均匀的骰子有n个面 ,投骰子,要求最后要把骰子的每一面都看到了 ,求扔骰子次数的期望

扔一次骰子有两种可能:

1、扔到了已出现过的面

2、出现未出现的面

例如:

1 + (1 + 0.5 * (1 + 0.5 * ...))

= 2 + 0.5 + 0.52 + 0.53 + ...

= 2 + 1 = 3

这是一个两个面的骰子:

首先第一次肯定是出现的一个从未出现过的面,那么期望就是  1

下一次有两种情况,出现一个新的面或者是出现一个原来已经出现过得,其中出现一个新的面的概率是 1

出现已经出现过得概率是  0.5(就只有两个面),出现已经出现的不符合题意,还需要继续投,知道出现所有的面

继续投的时候,是在出现了一个已经出现过的面的前提下,所以是在乘 0.5的基础上

又出现两种情况,一直下去

所以期望是:

  E = 1 + k / n (1 + k / n (1 + n / k * (...))) 

        = 1 + k / n + (k / n) ^ 2 + (k / n) ^ 3 + ...     //等比数列求和,循环看做无限大(1- (k / n) ^ max)就可以看做1

        = 1 + k / (n - k)

还可以用 dp 的方法来推

dp [i] =dp [i]*( i / n ) + dp [i+1] *( ( n - i )/ n )+1;

经过化简,推出

 dp[i]=dp[i+1]+(double)n/(n-i);

 

解释一下这个式子:

dp [ i ] : 代表的是 出现 i 面次数的期望值

出现当前面的期望 是从原来出现过的点数中出现的 期望值 +  剩下的点数出现一次的期望值 + 一定会出现那该点数的期望值( 1)

从原来出现过的点数中出现的 期望值 —— dp [i]*( i / n )  ( n 个中已经出现了 i 个)

剩下的点数出现一次的期望值—————— dp [i+1] *( ( n - i )/ n )  ( dp [ i+1] 的原因是,出现了已经出现过得点数,不符合题意,还需要继续向下找,所以代表的是下一步的操作,从剩余的选择一个没有出现的)

记住:求期望要逆推

Code:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#include<stack>
#define LL long long
using namespace std;
int main()
{
    int t,n;
    cin>>t;
    int flag=1;
    double dp[100002];
    while(t--)
    {
        scanf("%d",&n);
        memset(dp,0,sizeof(dp));
        for(int i=n-1;i>=0;i--)
            dp[i]=dp[i+1]+(double)n/(n-i);
        printf("Case %d: %.10f\n",flag++,dp[0]);
    }
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值