FOJ 2200 cleaning(环形dp)

本文探讨了一种特殊的大扫除人选选择问题,即在一圈人中选择若干人进行大扫除,但需避免选择距离为2的人。通过动态规划算法解决此问题,并提供了解决方案的AC代码。
Problem 2200 cleaning

Problem Description

N个人围成一圈在讨论大扫除的事情,需要选出K个人。但是每个人与他距离为2的人存在矛盾,所以这K个人中任意两个人的距离不能为2,他们想知道共有多少种方法。

Input

第一行包含一个数T(T<=100),表示测试数据的个数。

接下来每行有两个数N,K,N表示人数,K表示需要的人数(1<=N<=1000,1<=K<=N)。

Output

输出满足题意的方案数,方案数很大,所以请输出方案数mod 1,000,000,007 后的结果。

Sample Input

24 28 3

Sample Output

416 
 
 
先考虑一下线性的,环其实就是直线的一种变形,
dp[i][j]表示前i个人取j个人的情况,则dp[i][j]=dp[i-1][j]+dp[i-4][j-2]+dp[i-3][j-1];
//dp[i-1][j]表示不选第i个人
//dp[i-4][j-2]表示选第i和i-1个人,不选第i-2个人
//dp[i-3][j-1]表示选第i个人,不选第i-1和i-2
接下来变线成环,就是第1个和第n个合在一起了
(1)当1,n都不选时,为dp[n-2][k];
(2)当1,n都选时,为dp[n-6][k-2]
(3)当选1不选n时,这种情况要考虑下第2个选不选,总的为dp[n-6][k-2]+dp[n-5][k-1]
(4)当选n不选1时,与(3)是一样的;
 
 
AC代码:
 
 
# include <stdio.h>
# include <string.h>
typedef long long int ll;
const int mod=1000000007;
int dp[1010][1010];
int a[10][10];
int main(){
	int i, j, k, n, t;
	memset(dp, 0, sizeof(dp));
	dp[1][0]=dp[1][1]=dp[0][0]=1;
	dp[2][0]=1;dp[2][1]=2;dp[2][2]=1;
	dp[3][0]=1;dp[3][1]=3;dp[3][2]=2;
	for(i=4; i<=1000; i++){
		dp[i][0]=1;
		dp[i][1]=i;
		for(j=2; j<=i; j++){
			dp[i][j]=((dp[i-1][j]+dp[i-4][j-2])%mod+dp[i-3][j-1])%mod;
		}
	}
    a[1][1]=1;a[2][1]=1;a[2][2]=1;
    a[3][1]=3;a[3][2]=3;a[4][1]=4;
    a[4][2]=4;a[5][1]=1;a[5][2]=5;
	scanf("%d", &t);
	while(t--){
		scanf("%d%d", &n, &k);
		if(n<6){
			printf("%d\n", a[n][k]);
			continue;
		}
		ll ans=0;
		ans=ans+dp[n-2][k];
		ans=ans+dp[n-6][k-2];
		ans=ans+dp[n-6][k-2]+dp[n-5][k-1];
		ans=ans+dp[n-6][k-2]+dp[n-5][k-1];
		printf("%d\n", (int)(ans%mod));
	}
	return 0;
}

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值