概率DP

POJ 3744 Scout YYF I

这就是一个乱搞题,暴力发现TLE了,然后看了看discuss里说可以矩阵加速,想了一会才想明白怎么用矩阵,分着算的啊。先算f[num[i]-1]之类的,代码太长了,还是找找规律吧。。

#include <cstdio>

#include <cstring>

#include <iostream>

#include <map>

#include <algorithm>

#include <vector>

#include <string>

#include <queue>

using namespace std;

#define eps 1e-8

int num[11];

int judge(double x,double y)

{

    double t = x-y;

    if(t < 0)

    t = -t;

    if(t < eps)

    return 1;

    else

    return 0;

}

int main()

{

    int i,j,n,maxz;

    double p,f1,f2;

    while(scanf("%d%lf",&n,&p)!=EOF)

    {

        maxz = 0;

        for(i = 0; i < n; i ++)

        {

            scanf("%d",&num[i]);

            maxz = max(num[i],maxz);

        }

        sort(num,num+n);

        if(num[0] == 1)

        {

            printf("0.0000000\n");

        }

        else

        {

            f2 = 1;

            f1 = 0;

            for(i = 2; i <= maxz+1; i ++)

            {

                double t;

                for(j = 0;j < n;j ++)

                {

                    if(num[j] == i)

                    break;

                }

                if(j != n)

                {

                    swap(f2,f1);

                    f2 = 0;

                }

                else

                {

                    t = f2;

                    f2 = f2*p + f1*(1-p);

                    f1 = t;

                }

                if(judge(f1,f2))

                {

                    for(j = 0;j < n;j ++)

                    {

                        if(num[j] > i)

                        {

                            i = num[j]-1;

                            break;

                        }

                    }

                }

            }

            printf("%.7lf\n",f2);

        }

    }

    return 0;

}
View Code

 CodeForces 148D Bag of mice

乱推推,题意看清楚。

#include <cstdio>

#include <cstring>

#include <iostream>

#include <map>

#include <algorithm>

#include <vector>

using namespace std;

#define eps 1e-8

double dp[1001][1001];

int in[1001][1001];

double dfs(int w,int b)

{

    double t;

    if(in[w][b])

    return dp[w][b];

    if(w == 0)

    return 0;

    t = w*1.0/(w+b);

    in[w][b] = 1;

    if(b >= 2)

    {

        if(b-2 > 0)

        return dp[w][b] = t + b*1.0/(w+b)*(b-1)/(w+b-1)*(b-2)/(w+b-2)*dfs(w,b-3) + b*1.0/(w+b)*(b-1)/(w+b-1)*w/(w+b-2)*dfs(w-1,b-2);

        else

        return dp[w][b] = t + b*1.0/(w+b)*(b-1)/(w+b-1)*w/(w+b-2)*dfs(w-1,b-2);

    }

    return dp[w][b] = t;

}

int main()

{

    int n,m;

    scanf("%d%d",&n,&m);

    printf("%.9lf\n",dfs(n,m));

    return 0;

}
View Code

 HDU 3853   LOOPS

入门题。

#include <cstdio>

#include <cstring>

#include <iostream>

#include <map>

#include <algorithm>

#include <vector>

#include <string>

#include <queue>

using namespace std;

#define eps 1e-6

double dp[1001][1001];

double w[1001][1001][3];

int judge(double x)

{

    if(x < 0)

    x = -x;

    if(x < eps)

    return 1;

    else

    return 0;

}

int main()

{

    int m,n,i,j,k;

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        for(i = 0;i < n;i ++)

        {

            for(j = 0;j < m;j ++)

            {

                for(k = 0;k < 3;k ++)

                scanf("%lf",&w[i][j][k]);

            }

        }

        dp[n-1][m-1] = 0;

        for(i = n-1;i >= 0;i --)

        {

            for(j = m-1;j >= 0;j --)

            {

                if(i == n-1&&j == m-1) continue;

                if(judge(w[i][j][0]-1)) continue;

                dp[i][j] = (dp[i][j+1]*w[i][j][1] + dp[i+1][j]*w[i][j][2] + 2)/(1-w[i][j][0]);

            }

        }

        printf("%.3lf\n",dp[0][0]);

    }

    return 0;

}
View Code

 ZOJ 3640 Help Me Escape

硬做就行,取整符号,你认识吗...

#include <cstdio>

#include <cstring>

#include <iostream>

#include <map>

#include <algorithm>

#include <vector>

#include <cmath>

using namespace std;

#define eps 1e-8

double dp[20001];

int in[20001];

int c[101];

int n;

double dfs(int x)

{

    int i;

    if(in[x])

    return dp[x];

    double ans,t2;

    t2 = ((sqrt(5.0)+1))*0.5;

    ans = 0;

    for(i = 0;i < n;i ++)

    {

        if(x > c[i])

        ans += (int)(t2*c[i]*c[i]);

        else

        ans += dfs(x+c[i])+1;

    }

    ans /= n;

    in[x] = 1;

    return dp[x] = ans;

}

int main()

{

    int i,f;

    while(scanf("%d%d",&n,&f)!=EOF)

    {

        memset(in,0,sizeof(in));

        for(i = 0;i < n;i ++)

        scanf("%d",&c[i]);

        printf("%.3lf\n",dfs(f));

    }

    return 0;

}
View Code

ZOJ 3380 Patchouli's Spell Cards

这个题,完全就是组合DP的感觉。

题意要求至少有l个,求反面,所有的数字都是0-l-1就行了。

dp[i][j] 前j种,放了i个位置,枚举当前颜色,放0到l-1种,这个问题就是m个位置,插入n个相同的数,以前做过,把n插板,然后从m+1个空里选。

用java第一次TLE了,记忆化了一下fun函数,就过了。

import java.math.BigInteger;

import java.util.Scanner;



public class Main {

    static BigInteger c[][] = new BigInteger[101][101];

    static BigInteger s[][] = new BigInteger[110][110];

    static boolean in[][] = new boolean[110][110];

    public static BigInteger gcd(BigInteger a, BigInteger b) {

        if (b.compareTo(BigInteger.valueOf(0)) == 0)

            return a;

        else

            return gcd(b, a.mod(b));

    }



    public static BigInteger fun(int n, int m) {

        int minz, i;

        if(in[n][m])

            return s[n][m];

        if (n == 0 || m == 0)

            return BigInteger.valueOf(1);

        if (n < m + 1)

            minz = n;

        else

            minz = m + 1;

        BigInteger ans = BigInteger.valueOf(0);

        for (i = 1; i <= minz; i++) {

            ans = ans.add(c[m + 1][i].multiply(c[n - 1][i - 1]));

        }

        in[n][m] = true;

        return s[n][m] = ans;

    }



    public static void main(String args[]) {

        Scanner cin = new Scanner(System.in);

        BigInteger dp[][] = new BigInteger[101][101];

        int i, j, k, n, m, l;

        for (i = 0; i <= 100; i++) {

            for (j = 0; j <= 100; j++)

                c[i][j] = BigInteger.valueOf(0);

        }

        for (i = 0; i <= 100; i++)

            c[i][0] = BigInteger.valueOf(1);



        for (i = 1; i <= 100; i++) {

            for (j = 1; j <= 100; j++)

                c[i][j] = c[i - 1][j - 1].add(c[i - 1][j]);

        }

        while (cin.hasNext()) {

            m = cin.nextInt();

            n = cin.nextInt();

            l = cin.nextInt();

            if (l > m) {

                System.out.println("mukyu~");

                continue;

            }

            for (i = 0; i <= m; i++) {

                for (j = 0; j <= n; j++)

                    dp[i][j] = BigInteger.valueOf(0);

            }

            dp[0][0] = BigInteger.valueOf(1);

            for (i = 0; i < m; i++) {

                for (j = 0; j < n; j++) {

                    for (k = 0; k < l; k++) {

                        if (dp[i][j].compareTo(BigInteger.valueOf(0)) == 0)

                            continue;

                        if (i + k > m)

                            continue;

                        dp[i + k][j + 1] = dp[i + k][j + 1].add(dp[i][j]

                                .multiply(fun(i, k)));

                    }

                }

            }

            BigInteger ans = BigInteger.valueOf(n).pow(m);

            BigInteger res = BigInteger.valueOf(0);

            for (i = 1; i <= n; i++) {

                res = res.add(dp[m][i]);

            }

            BigInteger t = gcd(ans.subtract(res), ans);

            System.out.println(ans.subtract(res).divide(t) + "/"

                    + ans.divide(t));

        }



    }

}
View Code

 SGU 495 Kids and Prizes

感觉是神题呢,这是咋推的,我想了半天,硬做来了个二维的...看别人的题解,直接一位搞定。。。

#include <iostream>

#include <cstdio>

#include <cstring>

#include <string>

using namespace std;

int n,num;

double dp[100010];

double dfs(int step,int m)

{



    double ans;

    if(step == n)

    {

        return (m*1.0/num);

    }

    ans = (m*1.0/num)*(dfs(step+1,m-1) + 1);

    if(m != num)

    ans += (num-m)*1.0/num*dfs(step+1,m);

    return ans;

}

int main()

{

    int m,i;

//    while(scanf("%d%d",&m,&n)!=EOF)

//    {

//        num = m;

//        printf("%.9lf\n",dfs(1,m));

//    }

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        dp[1] = 1;

        for(i = 2;i <= m;i ++)

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

        double ans = 0;

        for(i = 1;i <= m;i ++)

        ans += dp[i];

        printf("%.10lf\n",ans);

    }

    return 0;

}
View Code

 ZOJ 3329 One Person Game

跟省赛的题非常相似,所有的dp[i]都用o1[i]*dp[0]+o2[i]表示,最后就解出dp[0]来了。

#include <cstdio>

using namespace std;

double o1[600];

double o2[600];

int main()

{

    int n,k1,k2,k3,a,b,c,i,j,k,u,t;

    scanf("%d",&t);

    while(t--)

    {

        scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c);

        for(i = n;i >= 0;i --)

        {

            o1[i] = 1.0/k1/k2/k3;

            o2[i] = 1;

            for(j = 1;j <= k1;j ++)

            {

                for(k = 1;k <= k2;k ++)

                {

                    for(u = 1;u <= k3;u ++)

                    {

                        if(i+j+k+u > n) continue;

                        if(j == a&&k == b&&u == c) continue;

                        o1[i] += 1.0/k1/k2/k3*o1[i+j+k+u];

                        o2[i] += 1.0/k1/k2/k3*o2[i+j+k+u];

                    }

                }

            }

        }

        printf("%.10lf\n",o2[0]/(1.0-o1[0]));

    }

    return 0;

}
View Code

 

 

你可能感兴趣的:(dp)