赞
踩
i:表示物品序号
j:表示背包大小
W [i]:表示第i件物品的重量
f[i,j]:表示在前i件物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值
f[i-1,j-Wi]:表示在前i-1件物品中选择若干件放在承重为j-Wi的背包中,可以取得的最大价值
Pi(j>=Wi):表示第i件物品的价值,要求背包大小j要大于此件物品的重量
f[i-1,j]:表示前i-1件物品中选择若干件放在承重为j的背包中,可以取得的最大价值
首先我们创立两个一维数组,用来存储大小和价值
再创立一个二维数组用来状态分析
分析背包问题我们是曲线救国,调用已经存在的数据元素来解决问题
物品个数是从1到n,然后分别得出该个数下的最大价值
我们要分析两个状态,放与不放,
第一种--不放i物品:f[i][j]=f[i-1][j](调用的是i-1状态下的最大值)
第二种--放i物品:f[i][j]=f[i-1] [j-v[i]] + w[i](此时同时是调用i-1个物品下的状态,
但是此时放物品那你要留空给这个物品放,so,此时调用的状态转移方程容量是j-v[i]条件下的,
最后再加上w[i]就是该状态下的value了)(当然,背包的容量要大于v[i]要不然放不下i 物品)
last but not least,我们要对两种状态,放与不放的价值大小进行判断
f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i])
最后输出则可。
- #include <bits/stdc++.h>
- using namespace std;
-
- const int N=1010;
- int main(){
- int n,m;
- int v[N],w[N];
- int f[N][N];
-
- cin>>n>>m;
- for (int i=1;i<=n;i++) cin>>v[i]>>w[i];
-
- for (int i=1;i<=n;i++)//物品个数 1-n
- for (int j=0;j<=m;j++){//容量 0-m
- f[i][j]=f[i-1][j];//先赋值给不放第i个,在下面再比较放与不妨
- if (j>=v[i]) f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);//f[i][j]= (1) f[i-1][j] (2) f[i-1][j-v[i]]+w[i]
- //第一种情况是取的是i-1个物品的最大 容量为j
- //第二种是[i-1]个但是把第i个放入的情况,那要取的是【i-1】,但是其内存要是j-v[i]--相当于留了一个地方存这个物品,取得是之前的最后再加上w[i]成为新的f[i][j]
- }
- cout<<f[n][m]<<endl;
- return 0;
- }
- n,m=map(int,input().split())#n是物品,m是容量
- v=[]#容量
- w=[]#价值
- v.append(0)
- w.append(0)
- f=[[0 for j in range(n+m)] for i in range(m+n)]
- for i in range(n):
- a,b=map(int,input().split())
- v.append(a)
- w.append(b)
- for i in range(1,n+1):
- for j in range(0,m+1):
- f[i][j]=f[i-1][j]
- if j>=v[i]:
- f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i])
- print(f[n][m])
- #include <bits/stdc++.h>
- using namespace std;
-
- const int N=1010;
-
- int v[N],w[N];
- int f[N][N];
- int n,m;
- int main()
- {
- cin>>n>>m;
- for (int i=1;i<=n;i++) cin>>v[i]>>w[i];
- for (int i=1;i<=n;i++)
- for (int j=0;j<=m;j++)
- for (int k=0;k*v[i]<=j;k++)
- f[i][j] = max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
- cout<<f[n][m]<<endl;
- return 0;
- }
- n, m = map(int, input().split())
- v, w = [0] * (n + 1), [0] * (n + 1)
-
- for i in range(1, n + 1):
- v[i], w[i] = map(int, input().split())
-
- # 二维:
- # 状态表示f[i][j] 选择前i个物品,总体积小于等于j的最大价值
- # 状态计算f[i][j] = max(f[i-1][j], f[i][j - v[i] + w[i] if j >= v[i])
- # 物品种类不限,所以max中第二项和0-1背包不同
-
- f = [[0] * (m + 1) for _ in range(n + 1)]
-
- for i in range(1, n + 1):
- for j in range(m + 1):
- f[i][j] = f[i-1][j]
- if j >= v[i]:
- f[i][j] = max(f[i][j], f[i][j-v[i]] + w[i])
-
- print(max(f[n]))
- n, m = map(int, input().split())
- v, w = [0] * (n + 1), [0] * (n + 1)
-
- for i in range(1, n + 1):
- v[i], w[i] = map(int, input().split())
- # 一维:f[j] 代表总体积小于等于j的最大价值
- # 因为每种物品数量不限,所以j从小到大更新,即可以使用前面当前层j更新后的结果
-
- f = [0] * (m + 1)
- for i in range(1, n + 1):
- for j in range(v[i], m + 1):
- f[j] = max(f[j], f[j-v[i]] + w[i])
- print(f[m])
- #include <bits/stdc++.h>
-
- using namespace std;
-
- const int N=110;
- int v[N],w[N],s[N];
- int f[N][N];
-
- int main()
- {
- int n,m;
- cin>>n>>m;
- for (int i=1;i<=n;i++) cin>>v[i]>>w[i]>>s[i];
- for (int i=1;i<=n;i++)
- for (int j=0;j<=m;j++){
- for(int k=0;k<=s[i] && k*v[i]<=j;k++)
- {
- f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+w[i]*k);
- }
- }
- cout<<f[n][m]<<endl;
- return 0;
- }
-
- n,v = map(int, input().split())
- goods = []
- for i in range(n):
- goods.append([int(i) for i in input().split()])
-
- new_goods = []
-
- for i in range(n):
- for j in range(goods[i][2]):
- new_goods.append(goods[i][0:2])
-
- goods = new_goods
- n = len(goods)
-
- dp = [0 for i in range(v+1)]
-
- for i in range(n):
- for j in range(v,-1,-1):
- if j>= goods[i][0]:
- dp[j] = max(dp[j], dp[j - goods[i][0]] + goods[i][1])
-
- print(dp[-1])
-
-
数字三角形属于线性DP问题。状态表示也是一个2维数组,f[i][j],i,j分别表示行与列
状态分析同时也是f[i][j]调用已经存在的状态值,该题的f[i][j]可以由两个方向过来,左上右上,
左上:f[i-1][j-1]+a[i][j]
右上:f[i-1][j]+a[i][j]
f [i][j]=max ( f [i-1] [j-1] + a[i] [j] , f [i-1] [j] + a[i] [j])
数字三角形题目还需注意左右次数的问题。
- #include<iostream>
-
- using namespace std;
-
- const int N = 510 , M = -1e9;;
-
- int n;
-
- int a[N][N];
- int f[N][N];
-
- int main(){
- cin >> n;
- for(int i = 1; i <= n; i++){
- for(int j = 1; j <= i; j++){
- cin >> a[i][j];
- }
- }
- for(int i = 0; i <= n; i++){
- for(int j = 0; j <= i+1; j++){
- //注意这里的循环判断条件 从零开始到最后一个数字的后一个位置都要初始化,因为他会用到左边界和右边界上的值.
- f[i][j] = M;
- }
- }
- f[1][1] = a[1][1];
-
- for(int i = 2; i <= n; i++){
- //前面第一个位置只有一种情况,所以从2开始
- for(int j = 1; j <= i; j++){
- f[i][j] = max(f[i-1][j-1]+a[i][j], f[i-1][j]+a[i][j]);
- }
- }
- if (n % 2 == 0) cout << max(f[n][n / 2], f[n][n / 2 + 1]) << '\n';
- else cout << f[n][n / 2 + 1];
- return 0;
- }
-
- n=int(input())
- arrs=[[0 for i in range(1,n+1+1)] for i in range(n+1)]#存数的数组
- arr=[[0 for i in range(1,n+3)] for i in range(n+1)]#动态规划状态调用数组
- for i in range(1,n+1):
- arrs[i][1:n]=list(map(int,input().split()))
- arr[1][1] =arrs[1][1]
- for i in range(2,n+1):
- for j in range(1,i+1):
- arr[i][j]=max(arr[i-1][j-1]+arrs[i][j],arr[i-1][j]+arrs[i][j])
-
- if n % 2 == 1:
- print(arr[-1][n//2 + 1])
- else:
- print(max(arr[-1][n//2],arr[-1][n//2+1]))
注:作者一些题目的解法可能并不是最优解,可以就行指出探讨。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。