• Ural 1225. Flags 斐波那契DP


    1225. Flags

    Time limit: 1.0 second
    Memory limit: 64 MB
    On the Day of the Flag of Russia a shop-owner decided to decorate the show-window of his shop with textile stripes of white, blue and red colors. He wants to satisfy the following conditions:
    1. Stripes of the same color cannot be placed next to each other.
    2. A blue stripe must always be placed between a white and a red or between a red and a white one.
    Determine the number of the ways to fulfill his wish.
    Example. For N = 3 result is following:
    Problem illustration

    Input

    N, the number of the stripes, 1 ≤ N ≤ 45.

    Output

    M, the number of the ways to decorate the shop-window.

    Sample

    inputoutput
    3
    4
    Problem Source: 2002-2003 ACM Central Region of Russia Quarterfinal Programming Contest, Rybinsk, October 2002

     
     
     
            最近被问到了这个问题,其实是一个很简单的DP,但就有人纠结为什么就变成了斐波那契。
            首先说下DP的思路:有三种状态,白、蓝、红,直接对应到0、1、2吧,于是可以定义一个数组dp[46][3],因为蓝的只能在白和红之间,所以只有一格的时候初始状态为:dp[1][0]=dp[1][2]=1,dp[1][1]=0。
            对于接下来的每格,这一格是红色依赖于前一格不是红色,这一格是白色依赖于前一格不是白色;另外假设如果前一格是蓝色,那么这一格是红/白色就依赖于前面第二格不是红/白色,于是有下面的递推:
                    白色:dp[i][0]=dp[i-1][2]+dp[i-2][2];
                    蓝色:dp[i][1]=dp[i-1][0]+dp[i-1][2];
                    红色:dp[i][2]=dp[i-1][0]+dp[i-2][0];
            最后把dp[N][0]和dp[N][2]加起来就是所有情况的总和了,因为最后一格无论如何也不可能是蓝色的。
     
     1 int main2() {
     2     int N;long long dp[46][3]={0};
     3     dp[1][0]=dp[1][2]=1;
     4     scanf("%d", &N);
     5     for(int i=2; i<=N; i++)
     6         dp[i][0]=dp[i-2][2]+dp[i-1][2],
     7         dp[i][1]=dp[i-1][0]+dp[i-1][2],
     8         dp[i][2]=dp[i-2][0]+dp[i-1][0];
     9     printf("%lld
    ",dp[N][0]+dp[N][2]);
    10     return 0;
    11 }
            然后我们可以发现一些有趣的事情,其实白色和红色的递推是相互依赖的,而蓝色根本不会有什么用,因为这一格是蓝色取决于前一格不是蓝色,即前一格是白色或红色的情况总和,这个数量并不能为下一格提供对前两格的有效判断。
            仔细观察发现,原来白色和红色就是两个相同的斐波那契数列,这样就好办了,两个合成一个,f[1]=f[2]=2,f[i]=f[i-1]+f[i-2],最后f[N]就是N格的情况总和。
     
    1 int main() {
    2     int N;long long dp[46]={0,2,2};
    3     scanf("%d", &N);
    4     for(int i=3; i<=N; i++)
    5         dp[i]=dp[i-1]+dp[i-2];
    6     printf("%lld
    ",dp[N]);
    7     return 0;
    8 }
            最后,一眼看出是斐波那契是如何做到的呢?首先无视蓝色,第一个格子f[1]=2,只有白/红两种情况,因为白/红不能连续出现,所以这一格是什么,已经定死了下一格是什么,于是第i个格子f[i]=f[i-1]。然后看看加入蓝色会发生什么:如果前一格是蓝色,那么当前格子一定是和前两格不同的颜色,则f[i]=f[i-2];综合考虑下,f[i]=f[i-1]+f[i-2]。
     
     
     
     
     
     
  • 相关阅读:
    解决android模拟器太大,小屏幕无法完全显示的问题
    寡人写的第一个HTML5页面
    android开发环境重装系统之后的配置
    PHP程序的一次重构记录
    重构遗留代码(1):金牌大师
    java加密算法研究
    理解Java常量池
    由一个项目看java TCP/IP Socket编程
    java List分组和排序处理
    JAVA获取方法参数名的分析(一)
  • 原文地址:https://www.cnblogs.com/BlackStorm/p/4702540.html
Copyright © 2020-2023  润新知