zoukankan      html  css  js  c++  java
  • 格子刷油漆(DP)

    格子刷油漆
        X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如图1所示),现需要把这些格子刷上保护漆。
        你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)
        比如:a d b c e f 就是合格的刷漆顺序。
        c e f d a b 是另一种合适的方案。
        当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
        输入数据为一个正整数(不大于1000)
        输出数据为一个正整数。
    例如:
    用户输入:
    2
    程序应该输出:
    24
    再例如:
    用户输入:
    3
    程序应该输出:
    96
    再例如:
    用户输入:
    22
    程序应该输出:
    359635897
    资源约定:
    峰值内存消耗 < 64M
    CPU消耗  < 1000ms

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
    注意: main函数需要返回0
    注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
    注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
    提交时,注意选择所期望的编译器类型(千万不要混淆c和cpp)。


    思路:

    名词解释相对的格子:一列之中,除了指定格子之外的另一个格子。
    1、构造两个动态规划数组和一个计数器sum,一个数组a[x],表示在2*x的格子条件下,从最边缘一列的一个角的格子出发,遍历全体格子的种类数,显然a[1]=1,另一个数组b[x],表示在2*x的格子条件下,从一个角的格子出发,遍历全体格子后回到与之相对的格子的种类数。如图所示,显然因为要考虑到回来的路径,因此除了出发点之外,每一列都只有2种选择方法,因此b[x]=2*b[x-1]  
    2、先考虑出发点在角上的问题,从一个角出发,只有3种可能性,(1)那就是先去相对的格子,然后前往下一列,这就简化成为从2*x-1列的格子中,从一个角出发遍历所有格子的问题,因为前往下一列的第一个格子有两种选法,因此a[x]+=2*a[x-1];(2)第二种可能性就是先去遍历其余格子,最后以相对的格子收尾。此时a[x]+= b[x];(3)第三种可能性较为复杂,先经过第二列的一次转折,然后到第三列的一个角上进行遍历。此时第二列有2种选法,第三列有2种选法,因此a[x]+=4*a[x-2]; 
    3、再去考虑出发点在中间的问题,如图所示,出发点在中间的时候,显然不能直接往下走,否则无法遍历所有点,应当是先遍历左边(右边)所有点,然后回到相对的点,然后遍历右边(左边)的点。注意先遍历的时候,必须是采用“遍历全体格子后回到与之相对的格子”的走法,否则无法遍历出发点正下方的点,而后遍历则不受限制。因此设从第i列开始出发,出发点有两种选法,第一落脚点又有两种走法,后遍历的第一落脚点又有两种走法,走完总走法数为2*(2*b[i-1]*2*a[n-i])+2*(2*b[n-i]*2*a[i-1]) (加法的前一半是先遍历左边,后一半是先遍历右边) 
    4、总走法数就是4*a[i](因为有4个角)+ 从2到第n-1列所有从中间走法数的和。

    下面是代码(vc6.0)编译通过。时间复杂度为o[n]

    #include <stdio.h>
    __int64 a[1001]={0};
    __int64 b[1001]={0};
    const int NUM=1000000007;
    int main()
    {
        int i,n;
        scanf("%d",&n);
     
      	b[1]=1;
        for (i=2;i<=n;i++)
            b[i]=(b[i-1]*2%NUM);
        a[1]=1;a[2]=6;
        for (i=3;i<=n;i++)
            a[i]=(2*a[i-1]+b[i]+4*a[i-2])%NUM;
        __int64 sum=4*a[n];
        for (i=2;i<n;i++)
          {
            sum+=((8*b[n-i]*a[i-1])%NUM+(8*a[n-i]*b[i-1])%NUM)%NUM;
            sum %= NUM;
          } 
            if(n==1)  sum=2 ; 
        printf("%I64d
    ",sum);
      
        return 0;
    } 



  • 相关阅读:
    简单Linux C线程池2
    简单xmlwriter类
    给10^7个有重复的整数排序(败者树)
    给10^7个无重复的整数排序
    将一个4字节整数的二进制表示中的001替换为011
    腾讯社招面试经历
    小闹钟 免费 开源 C# .net framework4
    国内外PHP开源建站程序
    用 .NET Memory Profiler 跟踪.net 应用内存使用情况基本应用篇 (转载)
    c# 语言 winform 项目中 control.parent 的使用 (原创)
  • 原文地址:https://www.cnblogs.com/zswbky/p/6717917.html
Copyright © 2011-2022 走看看