CF160 D

本文深入探讨了一道排列组合问题,通过动态规划算法的视角,揭示了如何解决这类问题的核心思路。文章详细阐述了动态规划在解决排列组合问题中的优势,特别是如何设置状态转移方程,以及如何利用已知状态来计算未知状态。通过实例代码的解析,读者能够清晰地理解动态规划在实际问题中的应用,并学会灵活运用这一强大工具解决类似问题。

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

题目链接:点击打开链接

这题有点像二维的01背包,主要是想到怎么设置dp[i][j]的含义。因为这里涉及到排列数,有很多种可能,但是最后一个数都是只有从0~n-1这几种可能,前面的数字可以全排列,后面的数字全排列。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 55
using namespace std;
int n,v;
int a[maxn];
double f[maxn],dp[maxn][maxn];//dp[i][j]以第i结尾,占有j容量的种类数
//则结果为sum(dp[i][j]*f[j]*f[n-j-1]/f[n])
void init()
{
    f[0]=f[1]=1;
    for(int i=2;i<=50;i++)
    {
        f[i]=f[i-1]*i;
    }
}
void DP()
{
    double ret=0;
    for(int i=0;i<n;i++)
    {
        //初始化
        memset(dp,0,sizeof(dp));//没放东西的时候只有最后一个放a[i]这一种情况,其他情况设置为0还是有点不懂,表所有状态必须从dp[0][0]开始么?
        dp[0][0]=1;
        for(int l=0;l<n;l++)
        {
            if(l!=i)
            {
                for(int j=n-1;j>0;j--)//个数限制
                {
                    for(int k=v;k>=a[l];k--)//容量限制
                    {
                        dp[j][k]+=dp[j-1][k-a[l]];//转移方程
                    }
                }
            }
        }
        for(int j=0;j<n;j++)
        {
            for(int k=0;k<=v-a[i];k++)
            {
                ret+=dp[j][k]*f[j]*f[n-j-1];
            }
        }
    }
    printf("%lf\n",ret/f[n]);
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    scanf("%d",&v);
    init();
    DP();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值