前置知识:状压DP

洛谷传送门

emm....看到题目,我第一个想到的就是枚举。暴力大法好!

具体怎么枚举?当然是子集枚举啦!枚举出每一个可能的砝码选择方案。对于每一个合法的(也就是选取数量等于\(n-m\)的)方案,求出这个方案能称出重量的数量。至于如何求重量的数量,枚举出这个方案所有的子方案,再对每个子方案的和去重。

这个方法实在是太暴力了

Code:

#include <bits/stdc++.h>
using namespace std;
#define MAXN 22
#define MAXA 2005
int n,m,a[MAXN],ans,sum[1<<22],cnt[1<<22];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
}
for(int i=1;i<(1<<n);i++){//状压
int high_bit=0,high_bit_num=0;
for(int j=31;j>=0;j--){
if((i>>j)&1){
high_bit=1<<j;
high_bit_num=j;
break;
}
}//求出当前方案的最高位
sum[i]=sum[i^high_bit]+a[high_bit_num+1];//转移。因为i是“按顺序”枚举的,所以去掉最高位后的方案一定枚举过了。
cnt[i]=cnt[i^high_bit]+1;
}
for(int i=1;i<(1<<n);i++){
if(cnt[i]==n-m){
set<int> heavy;//set有自动去重的功效
for(int j=1;j<=i;j++){
if((j|i)==i){
heavy.insert(sum[j]);//枚举每个子方案
}
}
ans=max(ans,int(heavy.size()));//取大
}
}
printf("%d\n",ans);
return 0;
}

但是,虽然暴力打得很爽,时间复杂度也非常爆炸。时间复杂度达到了可怕的\(O((2^{n})^2)\)! 所以,优化是必须的。

可以考虑对求重量的数量的过程进行优化。定义状态\(dp(i)\)代表当前方案能否称出重量\(i\),\(a(j)\)代表当前考虑的砝码(当然,这个砝码必须包含在当前方案里),容易想出像下面这样的状态转移方程:

\[dp(i)=dp(i-a(1)) \operatorname{OR} dp(i-a(2))...\operatorname{OR} dp(i-a(n))
\]

这个方程翻译成人话的意思就是:如果一个重量可以被组合出来,那么再加一个砝码也能被组合出来。反过来就是,如果一个重量减去一个砝码的重量能被组合出来,那么这个重量能够被组合出来。

有了状态转移方程,代码就非常好写了。

#include <bits/stdc++.h>
using namespace std;
#define MAXN 22
#define MAXA 2005
int n,m,a[MAXN],cnt[1<<22],dp[MAXA],ans;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
}
for(int i=1;i<(1<<n);i++){//状压
int high_bit=0,high_bit_num=0;
for(int j=31;j>=0;j--){
if((i>>j)&1){
high_bit=1<<j;
high_bit_num=j;
break;
}
}//求出当前方案的最高位
cnt[i]=cnt[i^high_bit]+1;//转移。因为i是“按顺序”枚举的,所以去掉最高位后的方案一定枚举过了。
}
for(int i=1;i<(1<<n);i++){
if(cnt[i]==n-m){
fill(dp,dp+2000+1,false);
dp[0]=true;
for(int j=1;j<=n;j++){
if(i>>(j-1)&1){//如果当前砝码在方案里才考虑
for(int k=2000;k>=a[j];k--){
dp[k]|=dp[k-a[j]];
}
}
}
int cnt=0;
for(int k=1;k<=2000;k++){
if(dp[k]){
cnt++;
}
}
ans=max(ans,cnt);
}
}
printf("%d\n",ans);
return 0;
}

时间复杂度是\(O(2^n\times n \times \max{a_i})\)仍然非常高,但比之前的不知道低到哪里去了,足以通过本题。

你都看到这儿了不考虑点一个赞吗

[状压DP]P1441 题解 砝码称重的更多相关文章

  1. POJ - 3254 Corn Fields(状压DP)题解

    思路: 参照blog,用状压DP做,和题解稍微有点不一样,我这里直接储存了状态而不是索引. 这一题的问题是怎么判断相邻不能种,我们用2进制来表示每一行的种植情况.我们将每一行所能够造的所有可能都打表( ...

  2. FJNU Fang G and his Friends(状压DP)题解

    Description     众所周知,fang G 有很多小伙伴,有一天,Fang G 打算带他们去玩有趣的游戏OOXX,这个游戏需要分成两组,有趣的是,每个人互相之间都有一个满意度,大家都想和自 ...

  3. POJ 2923 Relocation(状压DP)题解

    题意:有2辆车运货,每次同时出发,n(<10),各自装货容量c1 c2,问最少运几次运完. 思路:n比较小,打表打出所有能运的组合方式,用背包求出是否能一次运走.然后状压DP运的顺序. 代码: ...

  4. HDU 4272 LianLianKan(状压DP)题解

    题意:一个栈,每次可以选择和栈顶一样的数字,并且和栈顶距离小于6,然后同时消去他们,问能不能把所有的数消去 思路:一个数字最远能消去和他相距9的数,因为中间4个可以被他上面的消去.因为还要判断栈顶有没 ...

  5. HDU 4628 Pieces(状压DP)题解

    题意:n个字母,每次可以删掉一组非连续回文,问你最少删几次 思路:把所有回文找出来,然后状压DP 代码: #include<set> #include<map> #includ ...

  6. HDU 2825 Wireless Password(AC自动机 + 状压DP)题解

    题意:m个密码串,问你长度为n的至少含有k个不同密码串的密码有几个 思路:状压一下,在build的时候处理fail的时候要用 | 把所有的后缀都加上. 代码: #include<cmath> ...

  7. 洛谷P1879 [USACO06NOV]玉米田Corn Fields【状压DP】题解+AC代码

    题目描述 Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ...

  8. Codeforces 744C Hongcow Buys a Deck of Cards 状压dp (看题解)

    Hongcow Buys a Deck of Cards 啊啊啊, 为什么我连这种垃圾dp都写不出来.. 不是应该10分钟就该秒掉的题吗.. 从dp想到暴力然后gg, 没有想到把省下的红色开成一维. ...

  9. POJ 1185 炮兵阵地(状压DP)题解

    思路:和上一篇思路一样,但是这里要求最大能排几个,这里要开三维,记录上次和上上次的状态,再一一判定,状态转移方程为 dp[i][j][k] = max(dp[i][j][k],dp[i - 1][k] ...

随机推荐

  1. 第七章 vuex专题

    一.Vuex安装 一般在创建项目是会选择 Vuex,如果没有选择: cnpm install vuex  --save 使用: import Vuex from "vuex"; V ...

  2. PHP array_merge_recursive() 函数

    实例 把两个数组合并为一个数组: <?php$a1=array("a"=>"red","b"=>"green&q ...

  3. 5.10 省选模拟赛 拍卖 博弈 dp

    LINK:拍卖 比赛的时候 前面时间浪费的有点多 写这道题的时候 没剩多少时间了. 随便设了一个状态 就开始做了. 果然需要认真的思考.其实 从我的状态的状态转移中可以看出所有的结论. 这里 就不再赘 ...

  4. Java垃圾回收原来这么简单

    什么是垃圾回收? 垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存泄露.有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和 ...

  5. C++的常用输入及其优化以及注意事项

    $\mathcal{P.S:}$ 对于输入方式及其优化有了解的大佬可直接阅读$\mathcal{Part}$ $\mathcal{2}$ 特别鸣谢:@归斋目录: $\mathcal{Part}$ $\ ...

  6. Jvm相关文章

    深入理解JVM-内存模型(jmm)和GC https://www.jianshu.com/p/76959115d486

  7. mysql主主半同步

    1.半同步概述 先了解下mysql的几种复制 异步复制MySQL复制默认是异步复制,Master将事件写入binlog,提交事务,自身并不知道slave是否接收是否处理:缺点:不能保证所有事务都被所有 ...

  8. Python使用socketServer包搭建简易服务器过程详解

    官方提供了socketserver包去方便我们快速的搭建一个服务器框架. 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的 ...

  9. Java 图书管理项目

    思路总结: 1.使用空布局 2.构造方法里写初始打开的界面 3.return 意思是 "否则"  代替else if,一切归于平静 4.连接数据库时 db=new database ...

  10. data argumentation 数据增强汇总

    几何变换 flip:水平翻转,也叫镜像:垂直翻转 rotation:图片旋转一定的角度,这个可以通过opencv来操作,各个框架也有自己的算子 crop:随机裁剪,比如说,在ImageNet中可以将输 ...