timus 1260. Nudnik Photographer 动态规划

题目传送门

做完这题感觉dp像是一些状态在转移,由一个(多个)目前状态推到后一(多)个状态。

这个题目的意思是n个人要照相,n个人的年龄为1到n。站成一排,规定最左段是1岁的人,相邻两个人的年龄差不会超过2岁。问有多少总排队方案。

解法:

第i个人加入所产生的状态可以从第i-1个人加入产生的状态推过来。我们知道,第i个人至少会与i-1或i-2相邻。因此以[i-1]和[i-2]作为状态。可以分为四种状态:

① [i-1][i-2] 即 i-1,i-2相邻且i-1在i-2前

②[i-2][i-1]

③[i-1][i-2]....和[i-2][i-1]....   即[i-1][i-2]相邻但不在末尾(分析可知i-1,i-2是否在末尾与下一状态有密切关系,如果没有这种状态则从i-1推到i时会漏掉一些状态)

④[i-2]...[i-1] 即i-1,i-2不连序,分析知i-1必须在末尾。

我们很快可以得出结论:当加入第i个人时,状态②可推出状态①,状态①④可以推出状态②,状态①③可以推出③,①④可以推出②。

因此状态状态转移方程:

dp[1][i]=dp[2][i-1];
dp[2][i]=dp[2][i-1]+dp[4][i-1];
dp[3][i]=dp[1][i-1]+dp[3][i-1];
dp[4][i]=dp[1][i-1];

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
    int dp[5][60];
    memset(dp,0,sizeof(dp));
    dp[1][1]=1;
    dp[2][2]=1;
    for(int i=3;i<=55;i++){
        dp[1][i]=dp[2][i-1];
        dp[2][i]=dp[2][i-1]+dp[4][i-1];
        dp[3][i]=dp[1][i-1]+dp[3][i-1];
        dp[4][i]=dp[1][i-1];
    }
    int n;
    while(~scanf("%d",&n)){
        cout<<dp[1][n]+dp[2][n]+dp[3][n]+dp[4][n]<<endl;
    }
    return 0;
}

后来看网上有另一种代码感觉更简单。

对座位进行DP,当第一个是1,第二个是2的时候,组合为dp[i-1];当第一个是1,第二个是3的时候,第三个也确定了是2,组合为dp[i-3];还有最后一种情况是1357……8642。

所以DP方程为dp[i] = dp[i-1]+dp[i-3]+1。

#include <stdio.h>

int n;
int dp[100];

int main()
{
    scanf("%d", &n);
    dp[1] = 1;
    dp[2] = 1;
    dp[3] = 2;
    dp[4] = 4;
    for(int i = 5; i <= 55; ++i){
        dp[i] = dp[i-1]+dp[i-3]+1;
    }
    printf("%d", dp[n]);

    return 0;
}


 

posted @ 2015-03-09 20:15  Scale_the_heights  阅读(244)  评论(0编辑  收藏  举报