此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。
小菜一碟的背包
题目描述
有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 }
时间: 2024-11-07 02:27:15