1 条题解
-
0
思路与算法
用dp[i][j]表示氧气达到i、氮气达到j时的最低重量,超过需求的气量分别截断为m,n。初态dp[0][0]=0,其余无穷。每个气缸只处理一次,i,j都从大到小枚举,将旧状态更新到min(m,i+a)、min(n,j+b),代价加重量。最后读dp[m][n],无穷输出-1。
正确性说明
截断气量只合并已经达到相应需求的状态,不改变任何后续气缸能否达标。每个气缸加入或不加入覆盖所有子集;目标坐标不小于原坐标,倒序保证读取的状态尚未使用本气缸。截断导致的自环有正重量,不会改善原状态,故不产生重复使用。按气缸数归纳,所有状态都是最低重量,目标状态即所求。
复杂度
初始化O(mn),每个气缸枚举(m+1)(n+1)个状态,时间O(kmn),空间O(mn)。最大总重量不超过800000,普通int足够;无穷哨兵取大于此上界的值。
易错点
两种气体必须同时至少达标;气缸不可无限选。要双重倒序,不能只倒序一个维度。超过需求的气体要截断,否则会漏掉有用的大气量气缸。
参考代码(C++11)
#include <bits/stdc++.h> using namespace std; int main() { int m, n, k; cin >> m >> n >> k; const int INF = 1000000000; vector<vector<int>> d(m + 1, vector<int>(n + 1, INF)); d[0][0] = 0; while (k--) { int a, b, c; cin >> a >> b >> c; for (int i = m; i >= 0; --i) for (int j = n; j >= 0; --j) { int x = min(m, i + a), y = min(n, j + b); d[x][y] = min(d[x][y], d[i][j] + c); } } cout << (d[m][n] == INF ? -1 : d[m][n]) << "\n"; }
- 1