加载中...

期望dp

期望的线性性质:E(ax+by)=aE(X)+bE(Y)=p(X)×E(X)+p(Y)×E(Y)

dp(状态)的值:在当前状态下还需要多少论才能结束答案 所以输出的是dp(初始状态) dp(目的状态=0)
dp[i][j]=p1 * ( dp[i-1][j-1] + 1 ) + p2 * (dp[i-1][j-2] + 1 ) //+1是权值

1-n总长度的期望

到达某个结果的期望值 = 这个结果 * 从起始状态到这个状态的概率
f[i]=∑1/k*(w[i]+f(S[i])
f[i]表示从i走到n的期望 边界f(N)=0即n到n的期望是0 答案为f[1]
没有权值 : p(x)=p1x1+p2x2+....+pnxn
有权值: p(y)=(p1(x1+w)+p2(x2+w)+…+pn(xn+w))/n
从x走到y: E(y)=E(x)+∑pi∗wi

#include <iostream>
#include <cstring>

using namespace std;

const int N = 100010 , M = 2 * N;

double f[N];
int e[M] , ne[M] , w[M] , h[N] , idx;
int n ,m;
int d[N];

void add(int a , int b , int c)
{
    e[idx] = b , ne[idx] = h[a] ; w[idx] = c , h[a] = idx++;
}

double dp(int u)//记忆化搜索
{
    if(f[u] >= 0) return f[u];//如果见过
    f[u] = 0;
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i];
        f[u] += (w[i] + dp(j)) / d[u];//d表示出边多少  dp(j)这里使用了倒推
    }
    return f[u];
}


int main()
{
    cin >> n >> m;
    memset(h , -1 , sizeof h);

    while(m--)
    {
        int a , b , c;
        cin >> a >> b >> c;
        add(a , b , c);
        d[a]++;//出度++
    }

    memset(f , -1 , sizeof f);//初始化成一个不存在的数

    printf("%.2lf\n" , dp(1));//从1开始
    return 0;
}

扑克牌https://www.acwing.com/solution/content/49466/ 在一副牌里面臭拿a,b,c,d各个花色张牌 去拿到的期望

我们使用f(a, b, c, d, x, y)表示现在已经翻出a张黑桃,b张红桃,c张梅花,d张方块,且大小王的状态为x、y需要翻开的牌的张数的期望值。
大王或者小王,Admin 将会把它作为某种花色的牌放入对应堆中 所以其中x、y取值为04,03分别表示黑桃、红桃、梅花、方块,4表示还没有被翻出。
当前翻开的牌数记为sum,则sum = a+b+c+d+(x!=4)+(y!=4),考虑状态转移:
边界是如果所有花色的牌都达到的数量,则不用再翻牌了,返回0即可。最终的答案就是f(0, 0, 0, 0, 4, 4)。

#include <iostream>
#include <cstring>

using namespace std;

const int N = 14;
const double INF = 1e20;

int A, B, C, D;
double f[N][N][N][N][5][5];

double dp(int a, int b, int c, int d, int x, int y) {

    double &v = f[a][b][c][d][x][y];
    if (v >= 0) return v;
    int as = a + (x == 0) + (y == 0);
    int bs = b + (x == 1) + (y == 1);
    int cs = c + (x == 2) + (y == 2);
    int ds = d + (x == 3) + (y == 3);
    if (as >= A && bs >= B && cs >= C && ds >= D) return v = 0;

    int sum = a + b + c + d + (x != 4) + (y != 4);
    sum = 54 - sum;
    if (sum <= 0) return v = INF;  // 没有牌可以翻开了

    v = 1;  // 表示翻开一张牌
    if (a < 13) v += (13.0 - a) / sum * dp(a + 1, b, c, d, x, y);
    if (b < 13) v += (13.0 - b) / sum * dp(a, b + 1, c, d, x, y);
    if (c < 13) v += (13.0 - c) / sum * dp(a, b, c + 1, d, x, y);
    if (d < 13) v += (13.0 - d) / sum * dp(a, b, c, d + 1, x, y);
    if (x == 4) {
        double t = INF;
        for (int i = 0; i <= 3; i++) t = min(t, 1.0 / sum * dp(a, b, c, d, i, y));
        v += t;
    }
    if (y == 4) {
        double t = INF;
        for (int i = 0; i <= 3; i++) t = min(t, 1.0 / sum * dp(a, b, c, d, x, i));
        v += t;
    }
    return v;
}

int main() {

    cin >> A >> B >> C >> D;

    memset(f, -1, sizeof f);
    double t = dp(0, 0, 0, 0, 4, 4);
    if (t > INF / 2) t = -1;

    printf("%.3lf", t);

    return 0;
}

作者:ToLoveToFeel
链接:https://www.acwing.com/solution/content/49466/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


牛客麻将题 给定初始手牌 求最优策略下达到七对的期望轮数

最优:不会发生扔什么来什么 扔了之后不会捡回来
第一 关心手上还有多少个单着 卡池剩下多少张单的
第二 扔出的肯定是该扔的
dp[i][j]表示卡池中还剩i张没有摸过的牌 手上还有j张单牌 还需要多少次摸排才能胡牌的期望
dp[i][j]=p1 * ( dp[i-1][j-1] + 1 ) + p2 * (dp[i-1][j-2] + 1 )
p1概率是摸到单牌的概率,所以池子少了一张单牌但是手上的牌不变 +1表示新增了一轮摸牌了
p2表示摸到的牌可以和已经有的牌凑成了一对,所以池子里面少了一张手上的单牌少了一张 +1表示新增了一轮摸牌了
+1的值可能随题目要求改变
p1= (i-3j)/i //卡牌里面的牌数 - 3*j单牌 抽到不能凑对的牌
p2= (3j)/i

#include<bits/stdc++.h>
using namespace std;
int t;
map<string, int> cnt;
long long dp[150][15]; 
const long long mod = 1e9+7;
long long ksm(long long x,long long y)
{
    long long ans=1, tmp = x;;
    while(y)
    {
        if(y&1) ans = ans * tmp % mod;
        y >>= 1;
        tmp = tmp * tmp % mod;
    }
    return ans;
}
long long inv(long long x)
{
    return ksm(x, mod-2);
}
int dfs(int i, int j)//i为牌堆里面的牌 j为手上单牌 
{
    if (dp[i][j] != -1) return dp[i][j];
    
     if (j == 0) return 0;
     long long p1 =  (i-3*j) *inv(i) % mod;
    // if (i-3*j <= 0 ) p1 = 0;
     long long p2 = (3*j) *inv(i) % mod;
     //p1抽到其他单牌 p2抽到对应单牌  
     if(j==1) dp[i][j] = (p1* (dfs(i-1, j)+1) % mod +p2 * 1 % mod) %mod; //手里面只剩一张牌的时候可以直接胡牌 不需要花费轮数 +1
     else dp[i][j] = (p1* (dfs(i-1, j)+1) % mod +p2 * (dfs(i-1, j-2)+1)% mod) %mod;
                
     return dp[i][j];
}
int main()
{
    scanf("%d", &t);
    memset(dp, -1, sizeof(dp));
    int cas =0;
    while (t--)
    {
        string s;
        cin >> s;
        cnt.clear();
        for (int i = 0; i < 13; i++)
        {
            string c = "";
            c += s[2*i];
            c += s[2*i+1];
            cnt[c]++; 
        }
        int n = 0;
        for(auto it : cnt)
        {
            if (it.second == 1) n++;
        }
     
        cout <<"Case #"<<++cas<<": "<< dfs(123, n) << endl;
    }
}
posted @ 2022-08-16 18:00  liang302  阅读(40)  评论(0编辑  收藏  举报