1. 程式人生 > 其它 >P1858 多人揹包

P1858 多人揹包

# 原題連結 :

->https://www.luogu.com.cn/problem/P1858<-

# 題外話 :

好像許多題解區 daolaos 都引用了揹包九講裡面的一些很抽象的語言,題解區第一的 dalao 用了所謂“刷表”方式證明。也很模糊。本題解重講思路。

# 思路 :

此題大致同於 01 揹包;

重點在:

/*核心程式碼*/
for(int i=1;i<=n;i++)
{
for(int j=m;j>=v[i];j--)
{
int add=0,a=1,b=1;
while(add<=k)
{
if(f[j][a]>f[j-v[i]][b]+w[i])
{
x[
++add]=f[j][a++]; } else { x[++add]=f[j-v[i]][b++]+w[i]; } } for(int t=1;t<=k;t++) f[j][t]=x[t]; } }




其中 $ f[i][j] $ 表示前 i 個數據最 j 優解;

$ add $ 表示到第幾個優解了 , 所以只要 $ add\le k $ 都可進入狀態轉移;

$ x[i] $ 記錄當前否被以前的替換掉 ( 此處如 01 揹包 ),所以之後還要把 x 裡的值刷回去;

a 與 b 分別記錄現在、前面的優解;

就優解判斷否被更新。

# 完整CODE:

#include<bits/stdc++.h>
#define
int long long using namespace std; int f[5001][101],v[10001],w[100001],x[100001]; signed main() { int k,m,n; cin>>k>>m>>n; for(int i=1;i<=n;i++) { cin>>v[i]>>w[i]; } memset(f,~0x3f3f3f3f,sizeof(f)); f[0][1]=0; for(int i=1;i<=n;i++) { for(int j=m;j>=v[i];j--) { int add=0,a=1,b=1
; while(add<=k) { if(f[j][a]>f[j-v[i]][b]+w[i]) { x[++add]=f[j][a++]; } else { x[++add]=f[j-v[i]][b++]+w[i]; } } for(int t=1;t<=k;t++) f[j][t]=x[t]; } } int sum=0; for(int i=1;i<=k;i++) sum+=f[m][i]; cout<<sum<<'\n'; return 0; }