Luogu P1794 装备运输

来源:互联网 发布:wifi速度测试软件 编辑:程序博客网 时间:2024/05/16 07:19

正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!左边有个“赞”字,你就顺手把它点了吧

题目描述

德国放松对英国的进攻后,把矛头指向了东边——苏联。1943年初,东线的战斗进行到白热化阶段。据可靠情报,90余万德国军队在库尔斯克准备发动浩大攻势。因此,朱可夫元帅要求你立即从远东的军工厂运输大量装备支援库尔斯克前线。列车司机告诉你,一趟列车最多可以容纳V体积的武器装备,但是你可能不能装满,因为列车承受不了那么大的重量,一趟列车最多可以承载C单位的重量。同时,军工厂仓库提供给你一份装备清单,详细记录了每件装备的体积、重量和火力。为了有效支援朱可夫元帅,你要找到一种方案,使得总火力值最大。

输入输出格式

输入格式:

第一行:V和G表示最大体积和重量。

第二行:N表示仓库有N件装备。

第三到N + 2行:每行3个数Ti Vi Gi表示各装备的火力值、体积和重量。

输出格式:

输出一个数,表示可能获得的最大火力值。

输入输出样例

输入样例#1
6 5 410 2 220 3 2 40 4 3 30 3 3 
输出样例#1
50

说明

对于100%的数据,V,G,N≤500


典型二维费用背包问题

评测记录 440ms / 2746KB


最近刚好在学背包,然而这一题又是偶然点进的

所以这道题就是好神奇的二维费用背包了

所以我准备做一做

引用《背包九讲》的一段介绍的话:

  问题
  二维费用的背包问题是指:对于每件物品,具有两种不同的费用;选择这件物品必须同时付出这两种代价;对于每种代价都有一个可付出的最大值(背包容量)。问怎样选择物品可以得到最大的价值。设这两种代价分别为代价 1 和代价 2,第 i 件物品所需的两种代价分别为 a[i]和b[i]。两种代价可付出的最大值(两种背包容量)分别为 V 和 U。物品的价值为w[i]。
  算法
  费用加了一维,只需状态也加一维即可。设 f[i][v][u]表示前 i 件物品付出两种代价分别为 v 和 u 时可获得的最大价值。状态转移方程就是:f[i][v][u]=max{f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+w[i]}。如前述方法,可以只使用二维的数组:当每件物品只可以取一次时变量 v 和 u 采用顺序的循环,当物品有如完全背包问题时采用逆序的循环。当物品有如多重背包问题时拆分物品。
  物品总个数的限制
  有时,“二维费用”的条件是以这样一种隐含的方式给出的:最多只能取 M 件物品。这事实上相当于每件物品多了一种“件数”的费用,每个物品的件数费用均为 1,可以付出的最大件数费用为 M。换句话说,设 f[v][m]表示付出费用 v、最多选 m 件时可得到的最大价值,则根据物品的类型(01、完全、多重)用不同的方法循环更新,最后在 f[0..V][0..M]范围内寻找答案。另外,如果要求“恰取 M 件物品”,则在 f[0..V][M]范围内寻找答案。
  小结
  事实上,当发现由熟悉的动态规划题目变形得来的题目时,在原来的状态中加一纬以满足新的限制是一种比较通用的方法。希望你能从本讲中初步体会到这种方法。


《背包九讲》给出的算法,f是三维的,所以我在它的基础上稍作修改,改成二维的,这样数据大一点空间还足够。事实证明,这种改法不仅在理论上是可行的,事实也是。

所以,我很快AC了这道题:

#include <iostream>using namespace std;#define max(a, b) (((a)>(b))?(a):(b))int v, g, n;int t[510];int a[510];int b[510];int f[510][510];int main() {    cin >> v >> g >> n;    for(int i = 0; i < n; ++i) cin >> t[i] >> a[i] >> b[i];    for(int i = 0; i < n; ++i) {        for(int j = v; j >= a[i]; --j) {            for(int k = g; k >= b[i]; --k) {                f[j][k] = max(f[j][k], f[j-a[i]][k-b[i]]+t[i]);            }        }    } cout << f[v][g];    return 0;}

PS:我并不是一次就AC的,有两三次吧,是因为我把第15行的f[j][k]打成了f[j][j]。。。

原创粉丝点击