题目大意:n个盒子摆放成一排,当有3个以上U摆放在一起的时候,就会有危险,让你求出总共有多少中危险的情况。
小结:
DP,每放置一个新的盒子,都对应2种情况:
设f(n)=当盒子数目为n的情况下,符合要求的放置方法的个数。
(1)前面n-1个盒子已经能符合要求,则第n个盒子无论是U还是L,都满足情况。
(2)前面n-1个盒子不能符合要求,即只有最后4个满足情况LUUU并且前面并没有连续的三个U的情况才能满足情况。
然后就有
状态转移方程:dp[n]=2*dp[n-1]+(1<<(n-4))-dp[n-4]。
当然,还有另外一种想法,递推。
关于递推的思想,我作为新手的唯一感想就是这个想法的大致套路就是分类讨论了,在确保所有情况都已经掌握的情况下,再进行递推。
同样地,设dp[n]=n个盒子排列时满足条件的情况个数
则可得出递推方程:
然后就是关键的代码了,因为UVa我没有账号,所以无法确保我的代码一定能AC,但是测试当n=4,5,30的时候结果都是正确的,我想应该没什么问题吧.
DP做法:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<ctype.h>
using namespace std;
typedef long long ll;
int main()
{
int n;
ll dp[50];
memset(dp,0,sizeof(dp));
dp[3]=1;
dp[4]=3;
for(int i=5;i<=30;i++)
dp[i]=2*dp[i-1]+(1<<(i-4))-dp[i-4];
while(~scanf("%d",&n))
{
printf("%lld\n",dp[n]);
}
return 0;
}
递推做法:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
ll solve(ll *dp,int cur)
{
ll ans=0;
for(int i=1;i<=cur-3;i++)
ans+=((1<<(i-1))-dp[i-1])*(1<<(cur-i-3));
return (1<<(cur-3))+ans;
}
int main()
{
int n;
ll dp[35];
memset(dp,0,sizeof(dp));
dp[3]=1;
dp[4]=3;
for(int i=5;i<=30;i++)
{
dp[i]=solve(dp,i);
}
while(~scanf("%d",&n))
{
printf("%lld\n",dp[n]);
}
return 0;
}