前置知识:状压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. Python os.chmod() 方法

    概述 os.chmod() 方法用于更改文件或目录的权限.高佣联盟 www.cgewang.com 语法 chmod()方法语法格式如下: os.chmod(path, mode) 参数 path - ...

  2. AutoWired注解和Lazy延迟加载

    一.代码截图: @Lazy是延迟加载的意思, 容器启动时不创建对象, 当从容器中需要获取此对象时才创建. @Lazy//@Lazy注解可以用在类上, 还可以用在普通方法上,还可以用在构造方法上,还可以 ...

  3. layui 父页面获取弹窗传递的值 和 父页面传值给子弹窗的方法

    1.父页面获取子页面(弹窗)的值: 现在父页面页面加载方法中定义方法,专门用来获取从子页面的值 $(document).ready(function() { //拿到子窗口中传回的数据 functio ...

  4. 【JZOJ4726】种花 题解(贪心+堆)

    题目大意:在一个长度为$n$的环型序列中取出$m$个数使这$m$个数的和最大,且要求这$m$个数互不相邻. ---------------------- 考虑维护$nxt$和$lst$,即一个数的前驱 ...

  5. C++文件操作和模板

    1.数据层次 位 bit 字节 byte 域/记录 将所有记录顺序地写入一个文件---->顺序文件:一个有限字符构成的顺序字符流 C++标准库中:ifsteam,ofstream,fstream ...

  6. MySQL索引结构原理分析

    我们在学习MySQL的时候经常会听到索引这个词,大概也知道这是什么,但是深究下去又说不出什么道道来.下面将会比较全面的介绍一下关于索引! 1 索引是什么? 这里用百度百科的一句话来说,在关系数据库中, ...

  7. IDEA新增类的快捷键

    1.选中新建类所在包,鼠标右击.然后依次点击New——>Java Class就可以弹出输入类名的弹出框了.         2.选中新建类所在包,按下alt+insert然后选择弹出框中的Jav ...

  8. 来自灵魂的拷问——知道什么是SQL执行计划吗?

    面试官说:工作这么久了,应该知道sql执行计划吧,讲讲Sql的执行计划吧! 看了看面试官手臂上纹的大花臂和一串看不懂的韩文,吞了吞口水,暗示自己镇定点,整理了一下思绪缓缓的对面试官说:我不会 面试官: ...

  9. 微信小程序 progress 进度条 内部圆角及内部条渐变色

    微信小程序progress进度条内部圆角及渐变色 <view class="progress-box"> <progress percent="80&q ...

  10. RIPS源码阅读记录(二)

    Author: tr1ple 这部分主要分析scanner.php的逻辑,在token流重构完成后,此时ini_get是否包含auto_prepend_file或者auto_append_file 取 ...