poj 2151 (DP)

来源:互联网 发布:淘宝开店怎么做代理商 编辑:程序博客网 时间:2024/06/06 18:14

题意:m个题目,t个队伍,冠军最少的题目数目n,求每个队伍出题&&冠军的出题达到要求

解法:DP

            刚开始看到题目的时候,m的范围是30,就想到hash枚举C(m,n)的各种情况,求概率。真是最近想hash想到疯,说实话hash还学的没怎么样呢,至少我还不知道北京邀请赛最后一题的hash为什么要那么干。总体思路算是懂了那个题了。

            

          这个题和前几天codeforces的DP大同小异,那个题的题意是:k叉树,求一条路径,路径的加和为n,并且存在至少一个路为d。艾玛,要是之前做了这个题,估计我的CF还可以涨点分,stop!!!,不能意淫了,扯远了,立马回来。


          此题的

                      状态表示是dp[i][j][k],第i个队伍,前j个题,做出k个的概率。

                      状态的转移方程:dp[i][j][k]=dp[i][j-1][k-1]*tree[i][j].val+dp[i][j-1][k]*tree[i][j].reval。

                      {val代表做出这个题的概率,reval代表没做出这个题的概率}

#include<iostream>#include<cstring>#include<algorithm>#include<cstdlib>#include<vector>#include<cmath>#include<stdlib.h>#include<iomanip>#include<list>#include<deque>#include<map>#include <stdio.h>#include <deque>#define maxn 1005#define ull unsigned long long#define rep(i,n) for(i=0;i<n;i++)#define cle(a) memset(a,0,sizeof(a))const ull inf = 1LL << 61;using namespace std;bool cmp(int a,int b){    return a>b;}int used[33];double dp[maxn][33][33];struct node{    double val,reval;}tree[maxn][35];int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int m,n,t;    while(cin>>m>>t>>n)    {        cle(used);        if(m==0&&n==0&&t==0)break;        int i,j,k;        double ans1=1.00000001;        rep(i,t)        {            double temp=1.0;            rep(j,m)            {               cin>>tree[i][j].val;               tree[i][j].reval=(1.0-tree[i][j].val);                temp*=tree[i][j].reval;            }            ans1*=temp;        }        ans1=1-ans1;        double p1=ans1*1.0;//至少做出一个的概率        double p2=0;        cle(dp);        rep(i,t)        {            dp[i][0][0]=tree[i][0].reval;            dp[i][0][1]=tree[i][0].val;            for(j=1;j<m;j++)            {               for(k=0;k<=j+1;k++)               {                   if(k-1>=0)                   dp[i][j][k]=dp[i][j-1][k-1]*tree[i][j].val+dp[i][j-1][k]*tree[i][j].reval;                   else                   dp[i][j][k]=dp[i][j-1][k]*tree[i][j].reval;               }            }        }        double sum[maxn][33];//前多少的和        cle(sum);        rep(i,t)        {            sum[i][0]=dp[i][m-1][0];            for(k=0;k<=j+1;k++)            {                sum[i][k]+=dp[i][m-1][k];            }        }       /* rep(i,t)        {            rep(j,m+1)            {                cout<<sum[i][j]<<" ";            }            cout<<endl;        }*/        p2=1.0;        rep(i,t)        {            double ans=0.0;            for(j=1;j<=n-1;j++)            {                ans+=sum[i][j];            }            p2*=ans;//做出的是1 ~ n-1个        }        p1=1.0;        rep(i,t)        {            p1*=(1-dp[i][m-1][0]);//至少做出一个        }        double ans=p1-p2;        printf("%.3lf\n",ans);    }    return 0;}


            

0 0
原创粉丝点击