牛客--卡牌游戏 (概率DP 逆推)

题目链接:卡牌游戏

n个人,m张卡牌上有m个数字。庄家随机一张卡牌,数字为X,第X位出局,随后第X位的下一位做庄家,问,每个人最后获胜的概率是多少?

约瑟夫环的变形问题,这里每次等概率的抽牌,数字是随机的,
dp[i][j]: 还剩i个人时,第j个人获胜的概率 。
dp[1][1]=1.0 最后剩下的那个人获胜
从游戏的结局向前推,剩i人时,枚举m张卡牌,计算出下一局他的位置(也就是剩i-1人时),累加。我们算的是第j个人获胜的概率,如果刚好抽到他自己出局,忽略。

抽到出局的位置temp:
1,temp=j ,忽略
2,temp < j 时,他下一局的位置 j-temp;累加 dp[i-1][j-temp]
3,temp > j 时,他下一局的位置 i-temp+j;累加 dp[i-1] [i-temp+j]

#include<bits/stdc++.h>
#define ll long long
#define db double
using namespace std;
const int maxx=100;

double  dp[maxx][maxx];
int a[maxx];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++)
        scanf("%d",&a[i]);
    dp[1][1]=1.0;
    for(int i=2; i<=n; i++)
        for(int j=1; j<=i; j++)
            for(int k=1; k<=m; k++)
            {
                int temp=a[k]%i==0 ? i:a[k]%i;
                if(temp>j)
                    dp[i][j]+=(dp[i-1][i-temp+j]/(double)m);
                else if(temp<j)
                    dp[i][j]+=(dp[i-1][j-temp]/(double)m);

            }
            char ch='%';
        for(int i=1;i<=n;i++)
           printf("%.2lf%c ",dp[n][i]*100,ch);

    return 0;

}


上一篇:1281:最长上升子序列


下一篇:C# DateTime和String 相互处理