HDOJ 3664 Permutation Counting / UVALive 5092 DP

本文通过递推和动态规划方法解决了一个关于排列的问题,首先介绍了如何通过深度优先搜索生成所有可能的排列并统计符合条件的情况,接着给出了一个更高效的DP解决方案,并详细解释了其递推过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个题呢,一开始是用DP想的,但是没有按照DP的思路走,因为题目意思描述得很简单,显然是可以打表找规律的

先附上打表的程序

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;

int dp[10][10],n;
int num[10];
bool vis[10];

void calc(){
	//for(int i=1;i<=n;i++)
	//	printf("%d%c",num[i],i==n?'\n':' ');
	int res=0;
	for(int i=1;i<=n;i++)
		if (num[i]>i) res++;
	dp[n][res]++;
}

void dfs(int step){
	if (step>n) calc();
	for(int x=1;x<=n;x++)
		if (!vis[x]){
			num[step]=x;
			vis[x]=true;
			dfs(step+1);
			vis[x]=false;
		}
}

int main(){
	n=7;
	memset(dp,0,sizeof(dp));
	memset(vis,false,sizeof(vis));
	dfs(1);
	for(int i=0;i<=n;i++)
		printf("%d%c",dp[n][i],i==n?'\n':' ');
	return 0;
}

代码就是用dfs生成了所有的排列,然后根据题意统计,dp【i】【j】:有i个数字,j个根据题意的匹配

我们可以修改n,n=3,4,5,6,7,8,……这些小数据打出来一个表,然后可以来找规律(这是一种可行的方法)


但是dp的方法呢,来递推公式:

dp【i】【j】会怎么来:

第一部分:dp【i-1】【j】,最大的第i个数放在最后面

第二部分:dp【i-1】【j】*j,最大的第i个数与前i-1个数字中的j个比原来位置上的数大的数互换位置,匹配值不变

第三部分:dp【i-1】【j-1】*(i-1-(j-1)),因为要增加一个匹配,就不能在原来已经有匹配的位置上选择


代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;

#define ll long long
const int maxn=1010;
ll dp[maxn][maxn];
const int mod=1e9+7;

int main(){
	//freopen("input.txt","r",stdin);
	memset(dp,0,sizeof(dp));
	for(int i=1;i<=1000;i++){
		dp[i][0]=1;
		for(int j=1;j<=i;j++)
			dp[i][j]=(dp[i-1][j]*(j+1)+dp[i-1][j-1]*(i-j))%mod;
	}
		int n,k;
		while(scanf("%d%d",&n,&k)!=EOF)
			printf("%lld\n",dp[n][k]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值