HDU 5366 The mook jong
题目链接:
hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5366
bestcoder:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=613&pid=1003
Appoint description:
Description
![](../../data/images/C613-1001-1.jpg)
ZJiaQ want to become a strong man, so he decided to play the mook jong。ZJiaQ want to put some mook jongs in his backyard. His backyard consist of n bricks that is 1*1,so it is 1*n。ZJiaQ want to put a mook jong in a brick. because of the hands of the mook jong, the distance of two mook jongs should be equal or more than 2 bricks. Now ZJiaQ want to know how many ways can ZJiaQ put mook jongs legally(at least one mook jong).
ZJiaQ want to become a strong man, so he decided to play the mook jong。ZJiaQ want to put some mook jongs in his backyard. His backyard consist of n bricks that is 1*1,so it is 1*n。ZJiaQ want to put a mook jong in a brick. because of the hands of the mook jong, the distance of two mook jongs should be equal or more than 2 bricks. Now ZJiaQ want to know how many ways can ZJiaQ put mook jongs legally(at least one mook jong).
Input
There ar multiply cases. For each case, there is a single integer n( 1 < = n < = 60)
Output
Print the ways in a single line for each case.
Sample Input
1
2
3
4
5
6
Sample Output
1
2
3
5
8
12
题解:
方法一:
区间dp。
dp[i][j]表示前i个地砖放j个木人桩(其中第i个地砖肯定有放东西,要不然就不会是dp[i][j],而是dp[k][j](k<i) )
则易得转移方程 dp[i][j]=sum(dp[k][j-1]),其中k<i-2;
初始化要注意:dp[i][1]=1,而其他则都清零。
代码:
#include<iostream> #include<cstdio> using namespace std; const int maxn = 66; typedef long long LL; int n; LL dp[maxn][maxn],ans[maxn]; void pre() { memset(dp, 0, sizeof(dp)); for (int i = 1; i < maxn; i++) dp[i][1] = 1; for (int i = 2; i < maxn; i++) { for (int j = 2; j < i; j++) { for (int k = i - 3; k >= j-1; k--) { dp[i][j] += dp[k][j - 1]; } } } memset(ans, 0, sizeof(ans)); for (int i = 1; i <maxn; i++) { for (int j = 1; j <= i; j++) { ans[i] += dp[i][j]; } } for (int i = 2; i < maxn; i++) ans[i] += ans[i - 1]; } int main() { pre(); while (scanf("%d", &n) == 1) { printf("%lld\n", ans[n]); } return 0; }
方法二:
可以把题意理解为求满足下面两个条件的长度为n的01串总数
条件1、不能全为0
条件2、任意两个1之间必须有两个及以上的0相隔
dp[i][0]表示第i位为0时长度为i的所有的合法串;
dp[i][1]表示第i位为1时长度为i的所哟的合法串。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 6 const int maxn = 66; 7 typedef long long LL; 8 9 LL dp[maxn][2]; 10 11 int n; 12 13 void pre() { 14 memset(dp, 0, sizeof(dp)); 15 dp[1][0] = dp[1][1] = 1; 16 for (int i = 2; i < maxn; i++) { 17 if (i > 3) dp[i][1] = dp[i - 3][0] + dp[i - 3][1]; 18 //当i==2时只有01合法,当i==3时只有001合法。 19 else dp[i][1]=1; 20 dp[i][0] = dp[i - 1][0] + dp[i - 1][1]; 21 } 22 } 23 24 int main() { 25 pre(); 26 while (scanf("%d", &n) == 1) { 27 printf("%lld\n", dp[n][0] + dp[n][1] - 1); 28 } 29 return 0; 30 }