背包问题

01背包问题思想是将将总数进行拆分,拆分成每块钱(每个重量基数)。

算法实现是将每个物体抽象为一行,每一列为总数的细分,再分别从物体本身的价格(重量)到总数循环,每一次都进行f[i]=max{f[i],f[i-v[j]]+v[i]*w[i]}(f[i]为每一格的最大收益,v[i]为物体价格/重量,w[i]为物体价值) 的比较,这样执行完每一行都可以刷新这个价格(重量)区间的最大收益

  • 例题1 (01背包问题)

P1060 开心的金明

#include<iostream>
#include<algorithm>
using namespace std;

int N, m;
int sum[30010];

struct thing
{
	int price;
	int grade;
}things[30];

void input();//输入函数

int main()
{
	int i, j;
	input();
	for (i = 1; i <= m; i++)
		for (j =N ; j >=things[i].price; j--)//*从后往前,这样就不是被本行的计算覆盖
			sum[j] = max(sum[j], things[i].price*things[i].grade + sum[j - things[i].price]);//计算公式,将问题拆分成每块钱
	cout << sum[N];
	return 0;
}

void input()
{
	cin >> N >> m;
	int i;
	for (i = 1; i <= m; i++)
		cin >> things[i].price >> things[i].grade;
}
  • 例题2 (01背包问题)

P1164 小A点菜

#include<iostream>
using namespace std;
  
const int N = 120;
  
int v[N], f[N];
  
int main()
{
  	int n, m;
  	int i, j;
  	f[0] = 1;//当钱正好购买一个菜的时候情况
  	cin >> n >> m;
  	for (i = 1; i <= n; i++)
  		cin >> v[i];
  	for (i = 1; i <= n; i++)
  		for (j = m; j >= v[i]; j--)
  			f[j] = f[j] + f[j - v[i]];//f[j]为不买当前菜的情况数,f[j-v[i]]为买了当前菜用剩下的钱买其他菜的情况数
  	cout << f[m];
  	return 0;
  }
  • 例题3 (完全背包问题)

P1616 疯狂的采药

  #include<iostream>
  #include<algorithm>
  using namespace std;
  
  const int N = 10010;
  
  struct Med
  {
  	int time, value;
  }med[N];
  
  int sum[100010];
  
  int main()
  {
  	int T, M;
  	int i, j;
  	cin >> T >> M;
  	for (i = 1; i <= M; i++)
  		cin >> med[i].time >> med[i].value;
  	for (i = 1; i <= M; i++)
  		for (j = med[i].time; j <= T; j++)//只有这里跟01背包反过来,这样可以不断更新每一个状态的最大价值,可以做到一直取
  			sum[j] = max( sum[j],med[i].value + sum[j - med[i].time] );
  	cout << sum[T];
  	return 0;
  }
posted @ 2019-07-05 21:13  夜烛灯花  阅读(134)  评论(0)    收藏  举报