abc332:E - Lucky bag

状态压缩,dp

题目:E - Lucky bag (atcoder.jp)

代码如下:注释写的很详细了。

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
const int INF= 0x3f3f3f3f;
const int N=3e5+5e4;

int n,m;

double w[20];
double s[N];
double dp[20][N];

void solved(){
    double avg =s[(1<<n)-1]/m;      //每个袋子的平均权重
    for(int i=0;i<m;i++){           
        for(int j=(1<<n)-1;j>=0;j--){
            if(i==0){
                dp[i][j]=(s[j]-avg)*(s[j]-avg);  //第一个幸运袋,直接放入
            }else{
                dp[i][j]=dp[i-1][j]+avg*avg;  //先假设当前袋子不放东西(需加上(avg-0)^2)
                /*当用比特序列表示集合时,可以从 
                k=j 开始,反复用 (k−1)&j 替换 k 直到 k=0 来枚举与比特序列 
                j 相对应的集合子集。(变量 k 跨越了与 j 所有子集相对应的比特序列)*/
                for(int k=j;k;k=(k-1)&j){ //枚举子集
                /*状态转移方程式*/
          /*也可以是dp[i][j]=min(dp[i][j],dp[i-1][j^k]+(s[k]-avg)*(s[k]-avg)); */
                    dp[i][j]=min(dp[i][j],dp[i-1][j-k]+(s[k]-avg)*(s[k]-avg)); //dp[0][k]可换为(s[k]-avg)^2
                }
            }
        }
    }
    cout<<fixed<<setprecision(15)<<dp[m-1][(1<<n)-1]/m<<endl;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>w[i];
    for(int i=(1<<n)-1;i>=0;i--){       //有2^n个子集
        for(int j=0;j<n;j++){
            if((i>>j)&1){
                s[i]+=w[j];  //s[i]表示i的二进制中第j位是否放物品之和
            }
        }
    }
    //然后使用dp[i][j]表示0~i的袋子中放入了方案包含的物品的最小方差
    solved();
    return 0;
    
}

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值