UVA10081 Tight Words(dp)

Given is an alphabet {0,1,…,k}, 0 ≤ k ≤ 9. We say that a word of length n over this alphabet is tight if any two neighbour digits in the word do not differ by more than 1.
Input
Input is a sequence of lines, each line contains two integer numbers k and n, 1 ≤ n ≤ 100. Output
For each line of input, output the percentage of tight words of length n over the alphabet {0, 1, …, k} with 5 fractional digits.
Sample Input
41 25
35 87
Sample Output
100.00000
40.74074
17.38281
0.10130

题目大意:
一串数长度为n,由0~k 的数字组成。且所有相邻两个数字之差的绝对值不大于1。问符合这个要求的数 占所有长度为n的数的百分比。

思路:
还是从最简单的情况,1个数,2个数,3个数开始思考。。。于是定义:长度为i的tight words 有f[i]个。但是发现决定f[i]的因素有第i位本身是多少,,和第i-1位上的数是多少,,,于是就想到定义为二维的状态。f[i][j]表示第i位为j时,长度为i的tight words有多少个。
方程:f[i][j]=f[i-1][j-1]+f[i-1][j]+f[i-1][j+1];
边界条件:f[1][j]=1;(0<=j<=k);
答案:f[n][0-k]的和。
需要注意的是,因为要求得是百分比,如果直接把分母(k+1)^n算出来的话太大了,但是经过计算分子是可以存下的。所以就先用dp算出分子,再用不断的除以k就好了。
但是!!最重要的是精度问题!!!!!

这是第一种输出方法,f[i][j]定义的整数,在计算tot的时候转化为double来除以k

const double EPS=1e-9;
typedef long long LL;
typedef unsigned long long ULL;
ULL f[105][15],n,k;
int main()
{
    //freopen("in.txt","r",stdin);
    while(cin>>k>>n)
    {
        mem(f);
        for(int i=0;i<=k;i++) f[1][i]=1;
        for(int i=2;i<=n;i++)
            for(int j=0;j<=k;j++)
                if (j>0) f[i][j]=f[i-1][j-1]+f[i-1][j]+f[i-1][j+1];
                else f[i][j]=f[i-1][j]+f[i-1][j+1];
        double tot=0;       
        for(int i=0;i<=k;i++) tot+=f[n][i]; 
            k++;
         for(int i=1;i<=n;i++)
             tot=((double) (tot*EPS))/((double) (k*EPS));
    //  n=pow(k+1,n);
        printf("%.5lf\n",(double)(tot)*100.0);
    //  printf("%.5lf\n",((double) (tot*EPS))/((double) (n*EPS))*100.0);        
    }
    return 0;
}

这是ac的写法,f[i][j]就存为double ,同时在加的时候要不断的除以k最后直接把定义为double的tot加起来就是了。

const double EPS=1e-9;
typedef long long LL;
typedef unsigned long long ULL;
ULL n,k;
double f[110][15];
int main()
{
    //freopen("in.txt","r",stdin);
    while(cin>>k>>n)
    {
        mem(f);
        for(int i=0;i<=k;i++) f[1][i]=1.0;
        for(int i=2;i<=n;i++)
            for(int j=0;j<=k;j++)
                if (j>0) f[i][j]=1.0/(k+1)*(f[i-1][j-1]+f[i-1][j]+f[i-1][j+1]);
                else f[i][j]=1.0/(k+1)*(f[i-1][j]+f[i-1][j+1]);
        double tot=0.0;     
        for(int i=0;i<=k;i++) tot+=1.0/(k+1)*(f[n][i]); 
    //  n=pow(k+1,n);
        printf("%.5lf\n",tot*100.0);
    //  printf("%.5lf\n",((double) (tot*EPS))/((double) (n*EPS))*100.0);        
    }
    return 0;
}

其中的玄学还需要自己感悟qwq。。。。。

你可能感兴趣的:(dp,精度)