潜水员(二维背包)
题目描述
潜水员为了潜水要使用特殊的装备。他有一个带$2$种气体的气缸:一个为氧气,一个为氮气。让潜水员下潜的深度需要各种数量的氧和氮。潜水员有一定数量的气缸。每个气缸都有重量和气体容量。潜水员为了完成他的工作需要特定数量的氧和氮。他完成工作所需气缸的总重的最低限度的是多少?
例如:潜水员有$5$个气缸。每行三个数字为:氧,氮的(升)量和气缸的重量:
$3 \ 36\ 120\\10\ 25\ 129\\5\ 50\ 250\\1\ 45\ 130\\4\ 20\ 119$
如果潜水员需要$5$升的氧和$60$升的氮则总重最小为$249$($1,2$或者$4,5$号气缸)。
你的任务就是计算潜水员为了完成他的工作需要的气缸的重量的最低值。
输入格式
第一行有$2$个整数 $m,n$。它们表示氧,氮各自需要的量。
第二行为整数 $k$ 表示气缸的个数。
此后的 $k$ 行,每行包括$a_i,b_i,c_i$,$3$个整数。这些各自是:第$i$ 个气缸里的氧和氮的容量及汽缸重量。
输出格式
仅一行包含一个整数,为潜水员完成工作所需的气缸的重量总和的最低值。
样例数据
输入
5 60 5 3 36 120 10 25 129 5 50 250 1 45 130 4 20 119
输出
249
分析
令$Dp_{i,j}$表示携带$iL\ O_2$和$jL\ N_2$的最小质量,显然$Dp_{0,0}=0$,本题与其他背包题不同的是,携带气体量可以超出所需的量。令$Temp_1$表示当前所取$O_2$体积,$Temp_2$表示当前所取$N_2$体积,其中
因此我们可以得到总的状态转移方程为
代码
#include <bits/stdc++.h> #define Enter puts("") #define Space putchar(' ') #define MAXN 1000010 using namespace std; typedef long long ll; typedef double Db; inline ll Read() { ll Ans = 0; char Ch = getchar() , Las = ' '; while(!isdigit(Ch)) { Las = Ch; Ch = getchar(); } while(isdigit(Ch)) { Ans = (Ans << 3) + (Ans << 1) + Ch - '0'; Ch = getchar(); } if(Las == '-') Ans = -Ans; return Ans; } inline void Write(ll x) { if(x < 0) { x = -x; putchar('-'); } if(x >= 10) Write(x / 10); putchar(x % 10 + '0'); } int Count , Head[MAXN]; Db Dis[MAXN]; bool Visit[MAXN]; int Start , End; int m , n; int a[MAXN] , b[MAXN] , Weight[MAXN]; int Dp[1001][1001]; int main() { m = Read() , n = Read(); int k = Read(); for(int i = 1; i <= k; i++) a[i] = Read() , b[i] = Read() , Weight[i] = Read(); memset(Dp , 0x3f , sizeof(Dp)); Dp[0][0] = 0; for(int i = 1; i <= k; i++) for(int j = m; j >= 0; j--) for(int p = n; p >= 0; p--) { int Temp1 = min(m , j + a[i]); int Temp2 = min(n , p + b[i]); Dp[Temp1][Temp2] = min(Dp[Temp1][Temp2] , Dp[j][p] + Weight[i]); } Write(Dp[m][n]); return 0; } /* 5 60 5 3 36 120 10 25 129 5 50 250 1 45 130 4 20 119 */