Acwing1020_潜水员01背包+思维

故事扮演 提交于 2020-02-14 23:13:16

题目链接:https://www.acwing.com/problem/content/description/1022/

首先这道题目和普通的01背包看起来不一样,因为一般的01背包通常是闲置容量然后求价值的最大数值,而这道题目则是让我们需要满足2个一定的价值然后去选择最小的花费,价值可以超过预计的价值。
这里我直接开了三维,下面是解释:
f[i, j, k]:表示在1 - i这些罐子里面选,然后满足氧气j,氮气k的最小花费。
状态转移方程:

  1. 不选第i个罐子, 那么f[i, j, k] = f[i - 1, j, k];但是注意这里需要加限制条件,因为我们必须要满足当前j,k的需求,所以我们在一开始还需要去维护一下加入前面1 - i - 1所有罐子都选的两个数值sum_n, sum_m只有当sum_n >= j && sum_m >= k 的时候我们才可以不去选择第I个罐子。
  2. 选择第i个罐子,此时f[i, j, k] = min(f[i, j, k], f[i - 1, j - a, k - b]);同时这里也需要加限制条件,加入当前sum_n + a < j && sum_m + b < k,那么表示即使选择了第i个罐子也不能满足需求,此时我们应该跳出内层的2层循环,让i ++;还有一种情况当sum_n + a >= j && sum_m + b < k的时候我们只需要跳出sum_m的最内存循环即可;还有一点也需要注意,j - a 和 k - b 可能回小于0。
    代码一份:
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int N = 1005, M = 100;

int f[N][M][M];

int main(void) {
//	freopen("in.txt", "r", stdin);
	int n, m; 
	scanf("%d%d", &n, &m);
	int q; 
	scanf("%d", &q);
	
	memset(f, 0x3f, sizeof f);
	for(int i = 0; i <= q; i ++) f[i][0][0] = 0;

	int sum_n = 0, sum_m = 0;
	for(int i = 1; i <= q; i ++) {
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		int flag = 0;
		for(int j = 0; j <= n; j ++) {
			for(int k = 0; k <= m; k ++) {
				//不选第i个
				if(sum_n >= j && sum_m >= k) f[i][j][k] = f[i - 1][j][k];

				//选第i个 
				if(sum_n + a >= j && sum_m + b < k) {
					break;
				} else if(sum_n + a < j && sum_m + b < k) {
					flag = 2;
					break;
				}
				f[i][j][k] = min(f[i][j][k], f[i - 1][j - a < 0?0:j - a][k - b < 0?0:k - b] + c);
				
			}
			if(flag == 2) break;
		}
		
		sum_n += a, sum_m += b;
	}

	printf("%d\n", f[q][n][m]);

//	fclose(stdin);
	return 0;
}

总结:通过这道题目,我发现有些题目可能变一下就不知道怎么做了,这个时候我们需要冷静的去进行分析,看是不是加一些限制条件或者去维护更多的东西去进行一些变化,还有需要注意临界情况,对0需要多加关注。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!