你有一个背包,最多能容纳的体积是V。
现在有n种物品,每种物品有任意多个,第i种物品的体积为
,价值为
。
(1)求这个背包至多能装多大价值的物品?
(2)若背包恰好装满,求至多能装多大价值的物品?
第一行两个整数n和V,表示物品个数和背包体积。接下来n行,每行两个数和
,表示第i种物品的体积和价值。
输出有两行,第一行输出第一问的答案,第二行输出第二问的答案,如果无解请输出0。
2 6 5 10 3 1
10 2
3 8 3 10 9 1 10 1
20 0
无法恰好装满背包。
6 13 13 189 17 360 19 870 14 184 6 298 16 242
596 189
可以装5号物品2个,达到最大价值298*2=596,若要求恰好装满,只能装1个1号物品,价值为189.
import sys def solution(n,V,v,m): dp1 = [0 for _ in range(V+1)] dp2 = [float("-inf") for _ in range(V+1)] dp2[0] = 0 for i in range(V+1): for j in range(n): if i<v[j]:break #if dp2[i-v[j]] != float('-inf'):# 可以省略 dp1[i] = max(dp1[i],dp1[i-v[j]]+w[j]) dp2[i] = max(dp2[i],dp2[i-v[j]]+w[j]) #print(dp1) #print(dp2) if dp2[-1] == float("-inf"): dp2[-1] = 0 return dp1[-1],dp2[-1] if __name__ == "__main__": n,V = map(int, input().split()) v = [0 for _ in range(n)] w = [0 for _ in range(n)] p = [0 for _ in range(n)] for i in range(n): p[i] = list(map(int,input().split())) p = sorted(p, key=lambda x:(x[0],x[1])) v,w =zip(*p) #print(v,w) res1,res2 = solution(n,V,v,w) print(res1) print(res2)
#include<iostream> #include<cstring> using namespace std; const int N = 1010; int f[N]; int main() { int n, m; cin >> n >> m; memset(f, -0x3f, sizeof(f)); f[0] = 0; for(int i = 1; i <= n; i++) { int v, w; cin >> v >> w; for(int j = v; j <= m; j++) f[j] = max(f[j], f[j - v] + w); } int ret = 0; for(int i = 1; i <= m; i++) ret = max(ret, f[i]); if(f[m] < 0) f[m] = 0; cout << ret << endl; cout << f[m] << endl; return 0; }
#include<iostream> #include<vector> using namespace std; int n,V; //无需恰好装满条件下的最大价值 void func1(vector<int>& value,vector<int>& weight) { vector<int> dp(V+1); //dp[i][j]:在j容量的背包下,从前i件物品挑选,所能得到的最大价值 dp[0]=0; for(int i=0;i<n;i++) for(int j=weight[i];j<=V;j++)//正向推 dp[j]=max(dp[j],dp[j-weight[i]]+value[i]); cout<<dp[V]<<endl; } //需要恰好装满条件下的最大价值 void func2(vector<int>& value,vector<int>& weight) { vector<int> dp(V+1); dp[0]=0;//容量为0的背包,恰好装满下的价值只能为0 for(int i=1;i<=V;i++) dp[i]=-0x3f3f3f3f;//注意初始化方式的不同 for(int i=0;i<n;i++) for(int j=weight[i];j<=V;j++)//正向推 dp[j]=max(dp[j],dp[j-weight[i]]+value[i]); if(dp[V]<0) cout<<0<<endl; else cout<<dp[V]<<endl; } int main() { cin>>n>>V; vector<int> value(n),weight(n); for(int i=0;i<n;i++) cin>>weight[i]>>value[i]; func1(value,weight); func2(value,weight); return 0; }
#include <stdio.h> #include <limits.h> int max(int a, int b) { return (a > b ? a : b); } int main() { int n, m; scanf("%d %d", &n, &m); int v[n + 1], w[n + 1], dp[n + 1][m + 1]; v[0] = 0, w[0] = 0; for (int i = 0; i <= m; i++) { dp[0][i] = 0; } for (int i = 1; i <= n; i++) { dp[i][0] = 0; scanf("%d %d", &v[i], &w[i]); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (j<v[i]) { dp[i][j]=dp[i - 1][j]; } else { dp[i][j] = max(dp[i - 1][j],dp[i][j-v[i]]+w[i]); } } } printf("%d\n", dp[n][m]); for (int i = 0; i <= n; i++) { dp[i][0] = 0; } for (int i = 1; i <= m; i++) { dp[0][i] = INT_MIN; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (j<v[i]) { dp[i][j]=dp[i - 1][j]; } else { dp[i][j] = max(dp[i - 1][j],dp[i][j-v[i]]+w[i]); } } } printf("%d", (dp[n][m] > 0 ? dp[n][m] : 0)); return 0; }
#include <iostream> #include <algorithm> #include <cstring> using namespace std; const int N = 1002; int n, V, v[N], w[N]; int dp[N]; int main() { cin >> n >> V; for (int i = 1; i <= n; i++) cin >> v[i] >> w[i]; memset(dp, 0, sizeof(dp)); for (int i = 1; i <= n; i++) for (int j = v[i]; j <= V; j++) { dp[j] = max(dp[j], dp[j - v[i]] + w[i]); } cout << dp[V] << endl; memset(dp, -1, sizeof(dp)); dp[0] = 0; for (int i = 1; i <= n; i++) for (int j = v[i]; j <= V; j++) { if (dp[j - v[i]] != -1) dp[j] = max(dp[j], dp[j - v[i]] + w[i]); } dp[V] = (dp[V] == -1) ? 0:dp[V]; cout << dp[V] <<endl; return 0; }
#include <climits> #include <iostream> using namespace std; const int N = 1010; int n, m; int v[N], w[N]; int dp[N]; int dp2[N]; int main() { cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> v[i] >> w[i]; } for (int i = 1; i <= m; i++) { dp2[i] = INT_MIN; } for (int i = 1; i <= n; i++) { for (int j = v[i]; j <= m; j++) { dp[j] = max(dp[j], dp[j - v[i]] + w[i]); dp2[j] = max(dp2[j], dp2[j - v[i]] + w[i]); } } cout << dp[m] << endl; if(dp2[m] < 0){ cout << 0 << endl; }else{ cout << dp2[m] << endl; } return 0; }
#include <iostream> #include <vector> using namespace std; int main() { int n, V; cin>>n>>V; vector<int> v(n), w(n); for(int i=0; i<n; i++){ cin>>v[i]>>w[i]; } vector<int> dp1(V+1,0), dp2(V+1, -1); dp2[0] = 0; for(int i=0; i<n; i++){ for(int j=V; j>=v[i]; j--){ //逆向推 int temp1 = j-v[i], temp2=w[i]; while(temp1>=0){ dp1[j] = max(dp1[j], dp1[temp1]+temp2); if(dp2[temp1]>=0){ dp2[j] = max(dp2[j], dp2[temp1]+temp2); } temp1 -= v[i]; temp2 += w[i]; } } } cout<<dp1[V]<<endl; if(dp2[V]<0) cout<<0; else cout<<dp2[V]; return 0; }后面发现如果正向推,就可以了,因为不同于0-1背包每件物品只能装一次。代码如下:
#include <iostream> #include <vector> using namespace std; int main() { int n, V; cin>>n>>V; vector<int> v(n), w(n); for(int i=0; i<n; i++){ cin>>v[i]>>w[i]; } vector<int> dp1(V+1,0), dp2(V+1, -1); dp2[0] = 0; for(int i=0; i<n; i++){ for(int j=v[i]; j<=V; j++){//正向推 dp1[j] = max(dp1[j], dp1[j-v[i]]+w[i]); if(dp2[j-v[i]]>=0){ dp2[j] = max(dp2[j], dp2[j-v[i]]+w[i]); } } } cout<<dp1[V]<<endl; if(dp2[V]<0) cout<<0; else cout<<dp2[V]; return 0; }
#include <iostream> #include <string.h> using namespace std; const int N = 1010; int n, V, v[N], w[N]; int dp[N]; int main() { cin >> n >> V; for (int i = 1; i <= n; i++) cin >> v[i] >> w[i]; for (int i = 1; i <= n; i++) for (int j = v[i]; j <= V; j++) dp[j] = max(dp[j], dp[j-v[i]] + w[i]); cout << dp[V] << endl; memset(dp, 0, sizeof(dp)); for (int j = 1; j <= V; j++) dp[j] = -1; for (int i = 1; i <= n; i++) { for (int j = v[i]; j <= V; j++) { if(dp[j-v[i]] != -1) dp[j] = max(dp[j], dp[j-v[i]] + w[i]); } } cout << (dp[V] == -1 ? 0 : dp[V]) << endl; return 0; }
#include<iostream> #include<cstdio> #include<climits> using namespace std; const int N = 1000 + 10; int v[N], w[N], dp1[N], dp2[N]; int main(){ int n, m; while(scanf("%d%d", &n, &m) != EOF){ for(int i = 0; i < n; i++) scanf("%d%d", &w[i], &v[i]); fill(dp2, dp2 + m + 1, -INT_MAX); dp2[0] = 0; for(int i = 0; i < n; i++){ for(int j = w[i]; j <= m; j++){ dp1[j] = max(dp1[j], dp1[j - w[i]] + v[i]); dp2[j] = max(dp2[j], dp2[j - w[i]] + v[i]); } } printf("%d\n", dp1[m]); if(dp2[m] < 0) printf("0\n"); else printf("%d\n", dp2[m]); } return 0; }
import sys # 空间复杂度使用二维数组 def ks(n, V, P, M): dp = [[float("-inf") for _ in range(V+1)] for _ in range(n+1)] for x in range(len(dp)): dp[x][0] = 0 # for y in range(len(dp[0])): # dp[0][y] = 0 for i in range(1, n+1): for j in range(1, V+1): if j >= P[i]: for k in range(0, j//P[i]+1): dp[i][j] = max(dp[i][j], dp[i-1][j-k*P[i]]+k*M[i]) else: dp[i][j] = dp[i-1][j] print(max(max(dp))) if dp[-1][-1] == float("-inf"): print(0) else: print(dp[-1][-1]) # 通过19/20,算法超时 def ks_B(n, V, P, M): dp = [float("-inf") for _ in range(V+1)] dp[0] = 0 for i in range(1, n+1): for j in range(V, -1, -1): for k in range(0, j//P[i]+1): dp[j] = max(dp[j], dp[j-k*P[i]]+k*M[i]) print(max(dp)) if dp[-1] != float("-inf"): print(dp[-1]) else: print(0) return # 满足要求 # 思考:容量序列遍历为何可以使用正向序列?而且序列的起点可以为P[i]? # 完全背包问题,物品i没有数量限制; # 当 j < P[i]时,容量不足以容纳物品 i, # 相当于d[i][j] = d[i-1][j], 在O(n)复杂度的算法中也就是不更新内容,所以可以设置起点为P[i] def ks_C(n, V, P, M): dp = [float("-inf") for _ in range(V+1)] dp[0] = 0 for i in range(1, n+1): for j in range(P[i], V+1): dp[j] = max(dp[j], dp[j-P[i]]+M[i]) print(max(dp)) if dp[-1] != float("-inf"): print(dp[-1]) else: print(0) return line1 = [int(x) for x in sys.stdin.readline().split()] n = line1[0] V = line1[1] P = [0] M = [0] for line in sys.stdin: tmp = [int(x) for x in line.split()] P.append(tmp[0]) M.append(tmp[1]) ks_C(n, V, P, M)
def ans(): n, size = map(int,input().split(" ")) v, w = [] , [] for _ in range(n): t1, t2 = map(int,input().split(" ")) v.append(t1) w.append(t2) dp1 = [0] * (size+1) dp2 = [float("-inf")] * (size+1) dp2[0] = 0 for i in range(n): for j in range(1,size+1): if j >= v[i]: dp1[j] = max(dp1[j], dp1[j-v[i]] + w[i]) dp2[j] = max(dp2[j], dp2[j-v[i]] + w[i]) print(dp1[-1]) print(dp2[-1] if dp2[-1] != float("-inf") else 0) ans()