POJ 2537 Tight words DP

简单DP

题意:由0-k这些数字组成的长度为n的数(并满足某个条件)的个数占所有总数的比例。

(满足某个条件:各个位的数字与其相邻的数字之差不超过1.)

用数组dp[i][j]表示满足以j结尾,长度为i的数的个数;

则适当思考可以得

状态转移方程为 :
    dp[i][j]=dp[i-1][j-1]+dp[i-1][j]+dp[j+1];   (0<j<k)
    dp[i][j]=dp[i-1][j]+dp[i-1][j+1];           (j==0)
    dp[i][j]=dp[i-1][j]+dp[i][j-1];             (j==k)
这里要考虑是不是边界

AC代码

View Code
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
int main()
{
    int n, k, i, j;
    double dp[102][11];
    while(~scanf("%d%d",&k,&n))
    {
        for(i=0;i<=k;i++)
            dp[1][i]=1;
        for(i=2;i<=n;i++)
        {
            for(j=0;j<=k;j++)
                if(j==0)dp[i][j]=dp[i-1][j]+dp[i-1][j+1];
                else if(j==k)dp[i][j]=dp[i-1][j]+dp[i-1][j-1];
                else dp[i][j]=dp[i-1][j]+dp[i-1][j-1]+dp[i-1][j+1];
        }
        double s=0;
        for(i=0;i<=k;i++)
            s+=dp[n][i];
        printf("%.5f\n",s*100/pow(k+1.0,n));
    }
    return 0;
}

写成3个实在麻烦,把0-k都虚拟地加1,初始化时把所有dp[][]的值清零,进行代码复杂度优化

状态转移方程为 :
    dp[i][j]=dp[i-1][j-1]+dp[i-1][j]+dp[j+1];   (1<=j<=k+1)

 

 AC代码

View Code
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
int main()
{
    int n, k, i, j;
    double dp[103][11];
    while(~scanf("%d%d",&k,&n))
    {
        memset(dp,0,sizeof(dp));
        for(i=1;i<=k+1;i++)
            dp[1][i]=1;
        for(i=2;i<=n;i++)
        {
            for(j=1;j<=k+1;j++)
                dp[i][j]=dp[i-1][j]+dp[i-1][j-1]+dp[i-1][j+1];
        }
        double s=0;
        for(i=1;i<=k+1;i++)
            s+=dp[n][i];
        printf("%.5f\n",s*100/pow(k+1.0,n));
    }
    return 0;
}


 

心得:DP需要多加练习,有些DP是不难的,不要被DP吓到了。

        以后遇到这类边界问题适当转换一下就可以降低代码复杂度。

 

posted @ 2012-08-05 21:53  To be an ACMan  Views(284)  Comments(0)    收藏  举报