【洛谷P1858】多人背包
阿新 • • 發佈:2019-03-09
代碼 復雜度 for getchar() class getch sca int row
題目大意:求解 0-1 背包前 K 優解的和。
題解:首先,可知對於狀態 \(dp[j]\) 來說,能夠轉移到該狀態的只有 \(dp[j],dp[j-w[i]]\)。對於 K 優解來說,只需對狀態額外增加一個維度即可。接著,考慮狀態轉移的過程,即:需要從 \(dp[j][1...k]\rightarrow dp[j][1...k],dp[j-w[i]][1...k]\rightarrow dp[j][1...k]\),可以考慮每次取出兩堆數中的最大值進行比較,取較大的給當前狀態,時間復雜度較高。可以發現,對於兩個狀態序列來說,\(dp[j][k-1]>dp[j][k]\) ,即:每個狀態序列是單調遞減的,可以考慮采用雙指針遍歷方法,時間復雜度較低。
代碼如下
#include <bits/stdc++.h> using namespace std; const int maxn=210; const int maxv=5010; inline int read(){ int x=0,f=1;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch)); do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch)); return f*x; } int n,m,K,dp[maxv][51],v[maxn],w[maxn]; int tmp[51]; void read_and_parse(){ K=read(),m=read(),n=read(); for(int i=1;i<=n;i++)scanf("%d%d",&w[i],&v[i]); memset(dp,0xcf,sizeof(dp)); dp[0][1]=0; } void solve(){ for(int i=1;i<=n;i++) for(int j=m;j>=w[i];j--){ int x=1,y=1,tot=0; while(tot<=K){ if(dp[j][x]>dp[j-w[i]][y]+v[i])tmp[++tot]=dp[j][x++]; else tmp[++tot]=dp[j-w[i]][y++]+v[i]; } for(int k=1;k<=K;k++)dp[j][k]=tmp[k]; } long long ans=0; for(int i=1;i<=K;i++)ans+=dp[m][i]; printf("%lld\n",ans); } int main(){ read_and_parse(); solve(); return 0; }
【洛谷P1858】多人背包