概率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

 

 

posted @ 2014-05-12 15:51  Naix_x  阅读(197)  评论(0编辑  收藏  举报