九度1552 动态规划

http://ac.jobdu.com/problem.php?pid=1552

题目一看就是可以用dp的,但是对我来说找状态还是最困难的一件事。参考了别人的代码,才知道如果找合适的状态,并根据我自己的理解,定义了如下状态函数和状态转移方程:

f[i][0]表示从左数第i个位置上是男生的合法排列数,f[i][1]表示从左数第i个位置上是女生的合法排列数,由此可知其该女生左边一定是女生。然而仅仅有了合法排列数是不够的,我们还要记录第i个位置上是女生的非法排列数,即该女生左边是男生,记为f[i][2]。虽然这种排列是非法的,不是答案所需的,但是在递推过程中却是必不可少的,我目前做过的几道dp题中,往往要考虑这一点,不能随意将目前不合法的状态遗漏掉,因为随着i增加,不合法的状态也有可能变为合法状态。

状态转移方程如下:

f[i][0]=f[i-1][0]+f[i-1][1],第i个位置是男生的合法种类数可直接由第i-1个位置上是男生或女生得排列数得到,即在各合法的排列最右边加一个男生,依旧合法。

f[i][1]=f[i-1][1]+f[i-1][2],第i个位置是女生的合法排列,其左边一定是女生,f[i-1][1]中各排列最右两个都是女生,但是没有考虑最右是女生而其左边是男生的情况,该状态为非法状态,由f[i-1][2]算出。

f[i][2]=f[i-1][0],第i个位置是女生的非法排列,即在i-1位置上是男生的排列右边再加一个女生构成。

我也顺便练习了一下记忆化搜索的写法。代码如下:

#include <stdio.h>
#include <memory.h>
#define MOD 1000000007

long long f[1010][3];

long long dp(int n, int k)
{
	if (f[n][k]>=0) return f[n][k];
	if (n==0) return 0;
	else
	{
		if (k==0)
		{
			f[n][k]=dp(n-1,0)+dp(n-1,1);
		}
		else if (k==1)
		{
			f[n][k]=dp(n-1,1)+dp(n-1,2);
		}
		else //k==2
		{
			f[n][k]=dp(n-1,0);
		}
		f[n][k]%=MOD;
		return f[n][k];
	}
}

int main()
{
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);
	memset(f,-1,sizeof f);
	f[1][0]=1;
	f[1][1]=0;
	f[1][2]=1;
	int n;
	while (scanf("%d",&n)!=EOF)
	{
		long long ans=(dp(n,0)+dp(n,1))%MOD;
		printf("%lld\n",ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值