1. 程式人生 > >2017山東夏令營測驗 D5T1 題解

2017山東夏令營測驗 D5T1 題解

font 狀態轉移方程 include 輸入 n) 轉移 col ron pri

此文為博主原創題解,轉載時請通知博主,並把原文鏈接放在正文醒目位置。

小菜一碟的背包
題目描述
有n頭奶牛,每頭奶牛有食量w[i]和產奶量v[i],每天能夠提供W千克草料。選取奶牛使產奶總量盡可能大,問最大是多少。
輸入格式
第一行兩個整數 ,表示奶牛的數量和每天最多能提供的草
接下來i行,每行兩個整數,第i行表示第I頭奶牛的產奶量和食量
輸出格式
僅一行,輸出一個整數,表示每天最大的總產奶量
輸入樣例
8 40
10 9
12 11
11 12
10 10
8 11
7 9
8 10
9 10
輸出樣例
41
限制與約定
對於所有數據,1 ≤ n ≤ 100,1 ≤ wi,W ≤ 10^9,1 ≤ vi ≤ 10^7,w1 ≤ wi ≤ w1 + 3.



分析:

並不是小菜一碟...

由於W的範圍太大,不能用常規的01背包來做。

註意到w[]的波動範圍很小,所以我們可以將所有的w減去一個基數,f[i][j][k]表示前i頭奶牛中選取j頭,其食量(減去基數之後的)和為k。

逆向轉移。狀態轉移方程:f[i][j][k] = max(f[i+1][j][k],f[i+1][j+1][k+w[i+1]]+v[i+1]);

AC代碼:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 
 5 const
int MAXN = 105; 6 7 inline void read(int &x) 8 { 9 char ch = getchar(),c = ch;x = 0; 10 while(ch < 0 || ch > 9) c = ch,ch = getchar(); 11 while(ch >= 0 && ch <= 9) x = (x<<1)+(x<<3)+ch-0,ch = getchar(); 12 if(c == -) x = -x; 13 }
14 long long f[MAXN][MAXN][305]; 15 bool vis[MAXN][MAXN][305]; 16 //choose j cows sum value 17 int w[MAXN],v[MAXN],n,W; 18 int mn = 2e9; 19 20 int dp(int i,int j,int k) 21 { 22 if (1LL*j*mn+k>W) return -2e9;//裝不下了 23 if(i == n) return 0;//已經全部嘗試完 24 if(vis[i][j][k]) return f[i][j][k]; 25 vis[i][j][k] = true; 26 return f[i][j][k] = std::max(dp(i+1,j,k),dp(i+1,j+1,k+w[i+1])+v[i+1]); 27 } 28 29 int main() 30 { 31 read(n),read(W); 32 for(int i = 1;i <= n;++ i) 33 read(v[i]),read(w[i]),mn = std::min(w[i],mn); 34 mn --;//mn就是基準數 35 for(int i = 1;i <= n;++ i) 36 w[i] -= mn; 37 printf("%d\n",dp(0,0,0)); 38 }

2017山東夏令營測驗 D5T1 題解