简单递推 学到的一些皮毛,总结一下


本来是做DP专题的,但我觉得还是多试试从基础的递推开始训练。可能对Dp有多点帮助。做到最后也发现递推也是很精妙的啊!这些题目来自hdu。都是for beginner~~ 我觉得我还是踏实点的好~~ 继续努力~~

HDU 2044 一只小蜜蜂...
f(n) = f(n-1) + f(n-2) ; Fibonacci   

到 n 分别有两条路,n-1 和 n-2 。

一般这些题要注意用long long 型的,这个让我WA了几次~~ 

#include <iostream>

using namespace std;

int main()
{
    long long dp[51],i,j,n;
    dp[1] = 1;
    dp[2] = 2;
    for(i = 3;i < 51;i ++)
    dp[i] = dp[i-1] + dp[i - 2];
    while(cin>>n)
    {
        while(n --)
        {
            cin>>i>>j;
            cout<<dp[j-i]<<endl;
        }

    }
    return 0;
}
HDU 2045 不容易系列之(3)―― LELE的RPG难题

想像一下,如果你一开始不知道这题是递推题,我怎么去思考这道题?这题高中时是一种排列组合的题型。

要学会用分情况和假设的思维方式来考虑递推问题。

如果是分情况来看待这题,这题首尾颜色不一样的条件会使情况越分越多,并且可能导致不全面,所以要简化这题。

进行假设,假设首尾颜色可以一样,那么就会豁然开朗。即3*2^(n-1)种。然后要剪除颜色一样的情况,颜色首尾一样就是f(n-1)的情况了。所以结果就是f(n)=3*2^(n-1) - f(n-1);

#include <iostream>

using namespace std;

int main()
{
    long long  f[51],i,n,cot = 4;
    f[1] = 3;f[2] = 6;
    for(i = 3;i < 51;i ++)
    {
        f[i] = 3*cot-f[i-1];
        cot*=2;
    }
    while(cin>>n)
    cout<<f[n]<<endl;
    return 0;
}

HDU 2046 骨牌铺方格

递推题还有一种方法,就是枚举找规律,很明显,这题是Fibonacci。

分情况来分析这道题,因为是加东西上去,那在n-1拍好的情况下+1.只有一种情况,发现还有一些情况没考虑到,在n-2的情况下+2,也只有一种情况,发现所有情况都考虑到了,得到方程。

#include <iostream>
using namespace std;
int main(){
       __int64 f[51];
       int i,n;
       f[0]=1;
       f[1]=1;
       f[2]=2;
       f[3]=3;
       for(i=4;i<51;i++){
              f[i]=f[i-1]+f[i-2];
       }
       while(cin>>n){
              printf("%I64d\n",f[n]);
       }
       return 0;
}

HDU 2047 阿牛的EOF牛肉串

很明显这道题要分类出来讨论,分为结尾是 O的 f1 和 结尾不是 O的 f2。

结尾不是 O 的种数 : (上一次结尾是 O 的 + 上一次结尾不是 O 的)* 2 ;即是:f2(n+1) = 2 * ( f1(n) + f2(n) ) 。

然后很容易发现结尾是 O 的等于上一次结尾不是 O 的种数。 即 f1(n) = f2(n-1) 。

也就是说:f2(n+1) = 2* ( f2(n-1) + f2(n)); f1(n+1) = f2(n);  f1(1) = 1;f2(1) = 2;F(1) = 3; F(2) = 6;

于是 F(n+1) = 2*(F(n-1) + F(n)) ;

#include <iostream>
using namespace std;

int main()
{
    long long dp[50],i,n;
    dp[1] = 3;dp[2] = 8;
    for(i = 3;i < 41;i ++)
    {
        dp[i] = 2*(dp[i-2] + dp[i-1]);
    }
    while(cin>>n)
    {
        cout<<dp[n]<<endl;
    }
}

HDU 2048 神、上帝以及老天爷

错排,F(n) 表示n 人错排种数。如果把第i 个数放在非原位 k 上,则有n-1种。 此时 k 位的数可有两种情况: 1、放在 i 上,则有 F(n-2) 种。 2、放在非 i 上,则有F(n-1)种。

所以F(n) = (n-1) * (F(n-2) + F(n-1));  


#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
    int n,m,t,i;
    double M[34],N[34];
    double ans;
    M[1] = 0;
    M[2] = 1;
    N[0] = 1;N[1] = 1;N[2] = 2;
    for(i = 3;i < 34;i ++)
    {M[i] = (i-1)*(M[i-1]+M[i-2]);N[i]=i*N[i-1];}
    cin>>t;
        while(t--)
        {
            cin>>n;
            ans = double(M[n]/N[n]);
            //cout<<M[n]<<" "<<N[n]<<endl;
            printf("%.2lf%%\n",100*ans);
        }

    return 0;
}

 
HDU 2049 不容易系列之(4)――考新郎

也是错排。

#include <iostream>

using namespace std;

int main()
{
    int n,m,t,i;
    long long M[34],N[34];
    M[1] = 0;
    M[2] = 1;
    N[0] = 1;N[1] = 1;N[2] = 2;
    for(i = 3;i < 34;i ++)
    {M[i] = (i-1)*(M[i-1]+M[i-2]);N[i]=i*N[i-1];}
    cin>>t;

        while(t--)
        {
            cin>>n>>m;
            cout<<M[m]*(N[n]/N[m]/N[n-m])<<endl;
        }

    return 0;
}

看来做递推就是找规律,分类,假设,有点创造性思维。

你可能感兴趣的:(简单递推 学到的一些皮毛,总结一下)