HDU 2154 跳舞毯 | DP | 递推 | 规律
Description
由于长期缺乏运动,小黑发现自己的身材臃肿了许多,于是他想健身,更准确地说是减肥。
小黑买来一块圆形的毯子,把它们分成三等分,分别标上A,B,C,称之为“跳舞毯”,他的运动方式是每次都从A开始跳,每次都可以任意跳到其他块,但最后必须跳回A,且不能原地跳.为达到减肥效果,小黑每天都会坚持跳n次,有天他突然想知道当他跳n次时共几种跳法,结果想了好几天没想出来-_-
现在就请你帮帮他,算出总共有多少跳法。
小黑买来一块圆形的毯子,把它们分成三等分,分别标上A,B,C,称之为“跳舞毯”,他的运动方式是每次都从A开始跳,每次都可以任意跳到其他块,但最后必须跳回A,且不能原地跳.为达到减肥效果,小黑每天都会坚持跳n次,有天他突然想知道当他跳n次时共几种跳法,结果想了好几天没想出来-_-
现在就请你帮帮他,算出总共有多少跳法。
Input
测试输入包含若干测试用例。每个测试用例占一行,表示n的值(1<=n<=1000)。
当n为0时输入结束。
当n为0时输入结束。
Output
每个测试用例的输出占一行,由于跳法非常多,输出其对10000取模的结果.
Sample Input
2
3
4
0
Sample Output
2
2
6
1.DFS得出结果,找规律
#include <iostream> #include "cstdio" using namespace std; #define MOD 10000 int n,cnt; int dfs(char c,int k) { if(k==n+1) { if(c=='A') cnt++; return cnt%MOD; } if(c=='A'){ dfs('B',k+1); dfs('C',k+1); } else if(c=='B'){ dfs('A',k+1); dfs('C',k+1); } else if(c=='C'){ dfs('B',k+1); dfs('A',k+1); } } int main() { //freopen("out.txt","w",stdout); int ans=0; for(n=2;n<20;n++){ cnt=0; cout<<n<<" "<<dfs('A',1)<<endl; } return 0; }
4 6 5 10 6 22 7 42 8 86 9 170 10 342 11 682 12 1366 13 2730 14 5462 15 922 16 1846 17 3690 18 7382 19 4762
观察数据找到规律:
if(i%2==0)
a[i]=2*a[i-1]+2;
else a[i]=2*a[i-1]-2;
#include<cstdio> #include<iostream> #include<cstring> using namespace std; int main() { int i,n,step[1008]={0,0,2,2}; for(i=4; i<1002; i++)//打表 { if(i%2==0) step[i]=2*step[i-1]+2; else step[i]=2*step[i-1]-2; step[i]=step[i]%10000; } while(scanf("%d",&n)&&n!=0) { printf("%d\n",step[n]%10000); } return 0; }
参考:http://blog.csdn.net/castledrv/article/details/46897311
2.递推式f[i]=2^(i-1)-f[i-1] 进一步推出f[i]=2^(i-2)+f[i-2]
含义:
A_A B | C 2
A__A BC | CB 2
A___A BAB | CAC | BCB | CBC | BAC | CAB 2
即后四个空全排列-以A结尾的排列数
f[i]=2^(i-1)-f[i-1]
f[i-1]=2^(i-2)-f[i-2]
->
f[i]=2^(i-2)+f[i-2]
#include<iostream> using namespace std; #define mod 10000 int main() { int a[1600] = { 0,0,2,2 }; int n; int k = 4; for (int i = 4; i < 1001; i++)///打表 { a[i] = (k%mod + a[i - 2] % mod) % mod; k = k * 2 % mod; } while (cin >> n&&n) { cout << a[n] << endl; } return 0; }
参考:http://www.cnblogs.com/dream-wind/archive/2012/03/16/2400596.html
3.DP
dp[i][j]
j=1表示第i步红色的步数
j=2表示第i步在黄色的步数
j=3表示第i步在蓝色的步数
对于每次跳到红色的状态有:第i-1必须是在蓝色和黄色的地板上
所以dp[i][1]=dp[i-1][2]+dp[i-1][3];
第i步黄色也有dp[i][2]=dp[i-1][1]+dp[i-1][3];
第i步蓝色有dp[i][3]=dp[i-1][1]+dp[i-1][2];
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; int dp[1001][3]; int main() { dp[1][2]=1;int i; dp[1][3]=1;dp[1][1]=0; for(i=2;i<=1000;i++) { dp[i][1]=dp[i-1][2]+dp[i-1][3]; dp[i][2]=dp[i-1][1]+dp[i-1][3]; dp[i][3]=dp[i-1][1]+dp[i-1][2]; dp[i][1]=dp[i][1]%10000; dp[i][2]=dp[i][2]%10000; dp[i][3]=dp[i][3]%10000; } int n; while(scanf("%d",&n)&&n) { printf("%d\n",dp[n][1]); } return 0; }
参考:http://www.voidcn.com/article/p-pkzamxse-et.html