bzoj 3717: [PA2014]Pakowanie
阿新 • • 發佈:2017-10-12
如果能 href sum problem const algo def des mes
4 3
4 2 10 3
11 18 9
Description
你有n個物品和m個包。物品有重量,且不可被分割;包也有各自的容量。要把所有物品裝入包中,至少需要幾個包?
Input
第一行兩個整數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),分別表示包的容量。
Output
如果能夠裝下,輸出一個整數表示最少使用包的數目。若不能全部裝下,則輸出NIE。
Sample Input
4 2 10 3
11 18 9
Sample Output
2HINT
Source
鳴謝Jcvb
n很小,考慮狀壓;
首先背包肯定是要從大往小用的,sort一遍;
我們在dp轉移的時候需要知道3個量:
用到第幾個背包了,當前背包的剩余容量,已經放好的集合狀態;
我們用num[zt]表示放zt的物品用到第幾個背包了,用hav[zt]表示放zt的物品已經用了多少容量,sum[num[zt]-hav[zt]就是當前背包剩余的容量;
放入一個物品的轉移分兩種:
1.當前背包還能放,那麽直接放;
2.當前背包放不了,那麽新開一個背包;
//MADE BY QT666 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int N=100050; const int Inf=19260817; int num[1<<24],w[200],n,m; ll sum[200],hav[1<<24]; bool cmp(int a,int b){return a>b;} int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&w[i]); for(int i=1;i<=m;i++) scanf("%lld",&sum[i]); sort(sum+1,sum+1+m,cmp); for(int i=1;i<=m;i++) sum[i]=sum[i-1]+sum[i]; m=min(n,m); for(int i=1;i<1<<n;i++) hav[i]=3e12,num[i]=Inf; for(int zt=0;zt<1<<n;zt++){ if(hav[zt]==3e12) continue; for(int j=0;j<n;j++){ if(!(zt&(1<<j))){ int k=zt+(1<<j); if(sum[num[zt]]-hav[zt]<w[j+1]){ if(sum[num[zt]]+w[j+1]<hav[k]){ if(num[zt]==m||sum[num[zt]+1]-sum[num[zt]]<w[j+1]) continue; hav[k]=sum[num[zt]]+w[j+1]; num[k]=num[zt]+1; } } else{ if(hav[zt]+w[j+1]<hav[k]){ hav[k]=hav[zt]+w[j+1];num[k]=num[zt]; } } } } } if(num[(1<<n)-1]==Inf) puts("NIE"); else cout<<num[(1<<n)-1]<<endl; return 0; }
bzoj 3717: [PA2014]Pakowanie