[bzoj3717][PA2014]Pakowanie_动态规划_状压dp

Pakowanie bzoj-3717 PA-2014

题目大意:给你n个物品m个包,物品有体积包有容量,问装下这些物品最少用几个包。

注释:$1\le n\le 24$,$1\le m\le 100$



想法:以为是什么超级牛逼的背包dp,结果就是状压dp

状态:f[s]表示装s状态的物品需要多少背包,g[s]表示在f[s]的前提下,最大的背包剩余的容量。

转移:直接判断最后一个能不能装下当前物品,转移即可。

还有就是这个题卡常,只能直接用Lowbit枚举1,不能全枚举,会T... ...

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 17000000
#define lowbit(x)   (x&(-x))
using namespace std;
int n,m,tmp;
int f[N],g[N],a[N],c[101];
bool cmp(const int &a,const int &b){return a>b;}
int main()
{
	scanf("%d%d",&n,&m); int sum=(1<<n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=m;i++) scanf("%d",&c[i]); sort(c+1,c+m+1,cmp);
	for(int i=n;i;i--) a[(1<<(i-1))]=a[i];
	for(int i=1;i<sum;i++)
	{
		f[i]=m+1;g[i]=-1;
		for(int j=i;j;j-=tmp)
		{
			tmp=lowbit(j);int x=i-tmp;
			if(a[tmp]<=g[x]&&(f[x]<f[i]||(f[x]==f[i]&&g[x]-a[tmp]>g[i])))
				f[i]=f[x],g[i]=g[x]-a[tmp];
			else if((f[x]+1<f[i]||(f[x]+1==f[i]&&c[f[x]+1]>g[i]+a[tmp]))&&c[f[x]+1]>=a[tmp])
				f[i]=f[x]+1,g[i]=c[f[i]]-a[tmp];
		}
	}
	if(f[sum-1]>m) puts("NIE");
	else printf("%d\n",f[sum-1]);
	return 0;
}

小结:好题,虽然卡常... ...

原文地址:https://www.cnblogs.com/ShuraK/p/9375027.html

时间: 2024-10-07 16:23:43

[bzoj3717][PA2014]Pakowanie_动态规划_状压dp的相关文章

[bzoj1879][Sdoi2009]Bill的挑战_动态规划_状压dp

Bill的挑战 bzoj-1879 Sdoi-2009 题目大意: 注释:$1\le t \le 5$,$1\le m \le 15$,$1\le length \le 50$. 想法: 又是一个看数据范围想做法的题,我们想到状压dp. 看了题解... ...网上给的状态是f[len][s]表示长度为len满足状态s的字符串个数. 光看状态... ...可能算重啊?! 其实... ... 状态:dp[len][s]表示长度为len,能且只能满足状态为s的字符串个数. 转移:我们先预处理出g[i]

BZOJ_1076_[SCOI2008]奖励关_状压DP

题意: 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随机抛出k次宝物, 每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的宝物以后也不能再吃). 宝物一共有n种,系统每次抛出这n种宝物的概率都相同且相互独立.也就是说,即使前k-1次系统都抛出宝物1( 这种情况是有可能出现的,尽管概率非常小),第k次抛出各个宝物的概率依然均为1/n. 获取第i种宝物将得到Pi 分,但并不是每种宝物都是可以随意获取的.第i种宝物有一个前提宝物集合Si.只

[poj1185]炮兵阵地_状压dp

炮兵阵地 poj-1185 题目大意:给出n列m行,在其中添加炮兵,问最多能加的炮兵数. 注释:n<=100,m<=10.然后只能在平原的地方建立炮兵. 想法:第2到状压dp,++.这题显然是很经典的.设状态dp[i][j][k]表示第i行的状态为j,i-1行的状态为k的最多炮兵数.在转移时,枚举所有的合法炮兵排列(此处的合法数目是根据一行全为平原的时候能放置的合法炮兵数目),然后内层循环枚举dp[i-1]的i-1状态,进行特判更新即可.统计答案时,我们只需对于dp[n]的所有可能状态求最大值

[LuoguP2157][SDOI2009]学校食堂_状压dp

学校食堂 题目链接:https://www.luogu.org/problem/P2157 数据范围:略. 题解: 发现$B$特别小,很容易想到状压. 即在$dp$的时候弄出来$f_{(i,j,k)}$表示前$i - 1$个都打完了饭,状态$j$也已经打完饭了,当前打饭的是$i$,上一个打饭的是$i+k$这样能存的下. 转移的话需要枚举状态,但是没必要枚举完全因为毕竟是长度只有$7$. 看见了相邻两个人转移的代价之后,以为可以根据位运算能搞出点什么东西发现啥也搞不动. 我们可以适当地省略一些条件

[Cometoj#3 B]棋盘_状压dp

棋盘 题目链接:https://cometoj.com/contest/38/problem/B?problem_id=1535 数据范围:略. 题解: 因为行数特别小,所以$dp$的时候可以状压起来. 之后就非常傻逼了.... 代码: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define N 1

【bzoj3717】[PA2014]Pakowanie 状压dp

题目描述 你有n个物品和m个包.物品有重量,且不可被分割:包也有各自的容量.要把所有物品装入包中,至少需要几个包? 输入 第一行两个整数n,m(1<=n<=24,1<=m<=100),表示物品和包的数量.第二行有n个整数a[1],a[2],…,a[n](1<=a[i]<=10^8),分别表示物品的重量.第三行有m个整数c[1],c[2],…,c[m](1<=c[i]<=10^8),分别表示包的容量. 输出 如果能够装下,输出一个整数表示最少使用包的数目.若不

动态规划---状压dp

状压dp,就是把动态规划之中的一个个状态用二进制表示,主要运用位运算. 这里有一道例题:蓝书P639猛兽军团1 直接上代码,注释很详细 #include<cstdio> #include<iostream> #include<cstring> #define N 15 #define M 110 #define MAX 550 using namespace std; /* 见蓝书641页 */ int s[MAX]; // 记录一行可能的状态 int num[MAX]

[ An Ac a Day ^_^ ] POJ 3254 Corn Fields 状压dp

题意: 有一块n*m的土地 0代表不肥沃不可以放牛 1代表肥沃可以放牛 且相邻的草地不能同时放牛 问最多有多少种放牛的方法并对1e8取模 思路: 典型的状压dp 能状态压缩 能状态转移 能状态压缩的题的特点就是只有两种状态 所以用0 1表示两种状态 用位运算判断是否符合条件 然后将前一行的合理状态转移到后一行 最后统计最后一行的状态 dp[i][j]代表第i行以第j种状态放牛时有多少种不同的状态 (c++的语言特性是 封装 继承 多态~) 1 /* ***********************

nyoj1273 河南省第九届省赛_&quot;宣传墙&quot;、状压DP+矩阵幂加速

宣传墙 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 ALPHA 小镇风景美丽,道路整齐,干净,到此旅游的游客特别多.CBA 镇长准备在一条道路南 面 4*N 的墙上做一系列的宣传.为了统一规划,CBA 镇长要求每个宣传栏只能占相邻的两个方格 位置.但这条道路被另一条道路分割成左右两段.CBA 镇长想知道,若每个位置都贴上宣传栏, 左右两段各有有多少种不同的张贴方案. 例如: N=6,M=3, K=2, 左,右边各有 5 种不同的张贴方案 输入 第一行: T 表示