Acwing1020_潛水員01揹包+思維

題目鏈接: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需要多加關注。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章