bzoj3717 [PA2014]Pakowanie 狀壓dp
阿新 • • 發佈:2018-11-05
Description
你有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),分別表示包的容量。
如果能夠裝下,輸出一個整數表示最少使用包的數目。若不能全部裝下,則輸出NIE。
Solution
寫了一個隨機化過不去
考慮狀壓。我們設f[x]表示選取物品狀態為x時最少包的數量,g[x]表示選取物品狀態為x,答案為f[x]時最後一個包剩餘的最大空間
考慮轉移。我們列舉x中1的位置,然後把這個物品塞進包裡面就可以了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
#define drp(i,st,ed) for (register int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
#define lowbit(x) ((x)&(-(x)))
const int INF=10777216;
const int N=16778216;
int a[N],b[205],f[N],g[N],n,m;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x= x*10+ch-'0',ch=getchar());
return x*v;
}
bool cmp(int x,int y) {
return x>y;
}
int main(void) {
// freopen("data.in","r",stdin);
// freopen("myp.out","w",stdout);
n=read(),m=read(); int lim=(1<<n)-1;
rep(i,1,n) a[i]=read();
drp(i,n,1) a[1<<(i-1)]=a[i];
rep(i,1,m) b[i]=read();
std:: sort(b+1,b+m+1,cmp);
rep(i,1,lim) {
f[i]=INF;
for (int x=i;x;x-=lowbit(x)) {
int tmp=lowbit(x);
if (g[i-tmp]>=a[tmp]&&(f[i-tmp]<f[i]||(f[i-tmp]==f[i]&&g[i-tmp]-a[tmp]>g[i]))) {
f[i]=f[i-tmp];
g[i]=g[i-tmp]-a[tmp];
} else if (b[f[i-tmp]+1]>=a[tmp]&&(f[i-tmp]+1<f[i]||(f[i-tmp]+1==f[i]&&b[f[i-tmp]+1]-a[tmp]>g[i]))) {
f[i]=f[i-tmp]+1;
g[i]=b[f[i]]-a[tmp];
}
}
}
if (f[lim]>m) puts("NIE");
else printf("%d\n", f[lim]);
return 0;
}