#狀壓dp,揹包,貪心#洛谷 5997 [PA2014]Pakowanie
阿新 • • 發佈:2020-11-04
題目
你有 \(n\) 個物品和 \(m\) 個包。物品有重量,且不可被分割;
包也有各自的容量。要把所有物品裝入包中,至少需要幾個包?
分析
考慮物品的數量很小,首先優先選容量大的揹包,
設\(f[S]\)表示當前選擇的物品二進位制狀態所需要的揹包數量,
但這不夠,還要維護當前最後一個揹包能夠最大剩餘的容量\(g[S]\),
那當前就是考慮新開一個揹包或者是填入最後一個揹包
時間複雜度\(O(2^nn)\),但是時限5s,可以通過
程式碼
#include <cstdio> #include <cctype> #include <cstring> #include <algorithm> #define rr register using namespace std; const int N=25,M=1<<24; int two[N],a[N],n,m,b[N],dp[M],cho[M+1],f[M]; inline signed iut(){ rr int ans=0; rr char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans; } signed main(){ n=iut(),m=iut(),two[0]=1; for (rr int i=0;i<n;++i) two[i+1]=two[i]<<1; for (rr int i=0;i<n;++i) cho[two[i]]=i; for (rr int i=0;i<n;++i) a[i]=iut(); for (rr int i=1;i<=m;++i) b[i]=iut(); sort(a,a+n),reverse(a,a+n), sort(b+1,b+1+m),reverse(b+1,b+1+m), memset(dp,42,sizeof(dp)),dp[0]=0; for (rr int S=1;S<two[n];++S){ for (rr int j=S;j;j&=j-1){ rr int i=cho[-j&j],now=S^two[i]; if (f[now]>=a[i]&&(dp[now]<dp[S]||(dp[now]==dp[S]&&f[S]<f[now]-a[i]))) dp[S]=dp[now],f[S]=f[now]-a[i]; if (dp[now]<m&&b[dp[now]+1]>=a[i]&&(dp[now]+1<dp[S]||(dp[now]+1==dp[S]&&f[S]<b[dp[now]+1]-a[i]))) dp[S]=dp[now]+1,f[S]=b[dp[now]+1]-a[i]; } } if (dp[two[n]-1]>m) printf("NIE"); else printf("%d",dp[two[n]-1]); return 0; }