zoukankan      html  css  js  c++  java
  • 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]。
     
     
     
     
     
     
  • 相关阅读:
    SP笔记:交叉实现七行并成一行
    HTML tag 学习
    操作哈希表
    Efficient bipedal robots based on passivedynamic walkers
    Pushing People Around
    ZEROMOMENT PONTTHIRTY FIVE YEARS OF ITS LIFE

    Active Learning for RealTime Motion Controllers
    Accelerometerbased User Interfaces for the Control of a Physically Simulated Character
    Dynamic Response for Motion Capture Animation
  • 原文地址:https://www.cnblogs.com/BlackStorm/p/4702540.html
Copyright © 2011-2022 走看看