标签:
做完这题感觉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; }
timus 1260. Nudnik Photographer 动态规划
标签:
原文地址:http://www.cnblogs.com/Scale-the-heights/p/4324407.html