CF160 D

来源:互联网 发布:手机淘宝5.9.0旧版本 编辑:程序博客网 时间:2024/06/05 15:44

题目链接:点击打开链接

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

代码:

#include<iostream>#include<cstring>#include<cstdio>#define maxn 55using 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;}


原创粉丝点击