zoukankan      html  css  js  c++  java
  • 百度之星2013年4月27日竞赛题目一 Fir

    百度之星2个小时只能做1题已经成定式了....只求1题赚点小分就知足了..orz

      比赛一开始,看到第一题激动了半天,正好这几天在学概率dp,看来RP守恒真不是盖得= =,飞速敲完后,完美过了样例,正自恋着准备交,听到X神说被坑了...仔细一想,当时的想法确实是错误的。幸好还没交!

    错误代码1:

    思路:ans[i]表示长度为i的串的期望时间,则ans[i]=∑(max(ans[j-1],ans[i-j])+1)*(1/i) [j代表当前爆炸的位置],然后从前往后递推就行了

    View Code
    #include<stdio.h>
    double dp[410];
    double max(double x,double y){
        return x>y?x:y;
    }
    
    void init(){
        int i,pos;
        dp[0]=0;dp[1]=1;
        for(i=2;i<=400;i++){
            double temp=1.0/i;
            for(pos=1;pos<=i;pos++){
                dp[i]+=(max(dp[pos-1],dp[i-pos])+1)*temp;
            }
        }
    }
    int main()
    {
        int T,n;
        init();
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            printf("%lf\n",dp[n]);
        }
        return 0;
    }

    从上面可以看到,对于一个长度为n的串,分成a,b两段时,我们直接用a和b的期望来算的,实际上a,b之间再爆炸的时候是相互影响的,也就是不能分别独立出来算然后取最大值。

    想到这点之后出现了错误代码2:

    思路:dp[i][j]表示炸开以后的两段分别长i,j时,剩下时间的期望,则:

      dp[i][j]=∑(max(dp[k1-1][i-k1],dp[k2-1][j-k2])+1)*p  [k1,k2分别为2段炸开的位置]

      然后长为n的期望时间就是dp[n][0]

    View Code
    #include<stdio.h>
    #include<string.h>
    
    double dp[410][410];    //两段分别为a,b时的期望
    double max(double x,double y){
        return x>y?x:y;
    }
    
    void init()
    {
        int i,j,pos1,pos2;
        memset(dp,0,sizeof(dp));
        dp[0][0]=0;
        dp[0][1]=dp[1][0]=1,dp[1][1]=1;
        for(i=2;i<=400;i++){
            for(j=1;j<=i;j++){
                double temp=1.0/i/j;
                for(pos1=1;pos1<=i;pos1++)
                    for(pos2=1;pos2<=j;pos2++)
                        dp[i][j]+=(max(dp[pos1-1][i-pos1],dp[pos2-1][j-pos2])+1)*temp;
                    dp[j][i]=dp[i][j];
            }
            double temp=1.0/i;
            for(j=1;j<=i;j++)
                dp[i][0]+=(dp[j-1][i-j]+1)*temp;
            dp[0][i]=dp[i][0];
        }
    }
    
    int  main()
    {
        int T,n;
        init();
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            printf("%.5lf\n",dp[n][0]);
        }
        return 0;
    }

    代码2的改进是,考虑到了分成的a,b两个爆炸不是独立的,对每种情况暴力枚举,复杂度大概是O(n^4),出来以后完美过了样例,但是保险起见还是没敢交。

    后来听到Y神的想法觉得挺有道理,直接算概率确实很保险,因为上面第二种方法等于还是要用期望,而期望这个东西直接取最大值就会觉得怪怪的,直觉就是这样是错的。

    于是就诞生了第三种代码,正误未知,但是思路肯定不会错,因为算概率的话,每种状态的转移都是有理可依的,复杂度O(n^4),只能打表用:

    思路:dp[i][j]表示长度为i的串,j次爆炸完的概率,则:

      如果dp[k-1][j-1]存在

        dp[i][j]+=∑dp[k-1][j-1]*dp[i-k][h]*(1.0/i) (h小于等于i-k,小于等于j-1)

      如果dp[i-k][j-1]存在

        dp[i][j]+=∑dp[k-1][h]*dp[i-k][j-1]*(1.0/i) (h小于等于k-1,小于等于j-1)

      这两种都存在,则还要减去重复算的一种情况.

    View Code
    #include<stdio.h>
    #include<string.h>
    double dp[410][410];//长度m用n次概率
    
    void init()
    {
        int i,j,k,pos,lenth1,lenth2;
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        dp[1][0]=dp[0][1]=0;
        dp[1][1]=1;
        for(i=2;i<=400;i++){
            double temp=1.0/i;
            for(j=1;j<=i;j++){    //分的次数
                for(pos=1;pos<=i;pos++){    //爆炸的位置
                    lenth1=pos-1;    //前一段长度
                    lenth2=i-pos;    //后一段长度
                    for(k=0;k<=j-1&&k<=lenth1;k++)
                        dp[i][j]+=dp[lenth2][j-1]*dp[lenth1][k]*temp;
                    for(k=0;k<=j-1&&k<=lenth2;k++)
                        dp[i][j]+=dp[lenth1][j-1]*dp[lenth2][k]*temp;
                    if(dp[lenth1][j-1]&&dp[lenth2][j-1])                //减掉重复,这一步容易忘!找了好久
                        dp[i][j]-=dp[lenth1][j-1]*dp[lenth2][j-1]*temp;
                }
            }
        }
    }
    int main()
    {
        int T,n;
        freopen("input.txt", "rt", stdin);
        freopen("output.txt", "wt", stdout);
        init();
        /*scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            double ans=0;
            for(int i=1;i<=n;i++)
                ans+=dp[n][i]*i;
            printf("%.5lf\n",ans);
        }*/
        for(int i=1;i<=400;i++)
        {
            double ans=0;
            for(int j=1;j<=i;j++)
                ans+=dp[i][j]*j;
            printf("%.5lf,",ans);
        }
    }

    这个代码调好以后已经只剩5分钟了...确定n=10和n=400的正确性后...不管三七二十一直接交了..求RP爆发吧

    总体来说还是我太弱了,概率dp这个东西,没有确定的递推式还是不要胡乱假设的好~

  • 相关阅读:
    如何不加班,以前问题的答案
    django部署
    djangocms安装技巧
    django_cms安装技巧
    sublime text 3插件
    昨日总结2016年1月11日
    django例子,question_text为中文时候报错
    关于django访问默认后台admin的时候提示403错误,
    laravel安装学习步骤
    关于composer安装插件时候提示找不到fxp插件时候的解决办法
  • 原文地址:https://www.cnblogs.com/SolarWings/p/3048163.html
Copyright © 2011-2022 走看看