SPOJ 181 - Scuba diver 二维背包

潜水员要潜水,给出n个气缸(1<=n<=1000),每个气缸中有氧气量为ti,氮气量为ai,气缸重量为wi(1<=ti<=21,1<=ai<=79,1<=wi<=800)。现在潜水员需要量为t的氧气,量为a的氮气(1<=t<=21,1<=a<=79),问选哪些气缸,使得重量最小。

【背包】二维背包问题,不同的是这个要选的物品占两种容量至少为t和a。

设dp[i][j][k]为氧气量为j,氮气量为k时的最小重量

dp[i][j][k]=min{ dp [ i-1 ] [ j-t[i] ] [ k-a[i] ] + w[i] }

显然第一维可以在用循环覆盖省略掉

一开始我这样是这样写的

for (i=1;i<=m;i++)
{
    for (j=ti;j>=0;j--)
        {
        for (k=ai;k>=0;k--)
        {
            if (dp[j+t[i]][k+a[i]]>dp[j][k]+w[i])
            {
                dp[j+t[i]][k+a[i]]=dp[j][k]+w[i];
                if (j+t[i]>=ti && k+a[i]>=ai) ans=min(ans,dp[j+t[i]][k+a[i]]);
            }
        }
    }
}

然后就WA了,一开始怎么也找不到错误,后来发现是循环边界有问题,假如数据

1 5
3
1 1 3
1 2 4
1 2 5

显然答案是三个全部都用上,

当扫描到第三个物品时,j必须是2,才能假如该物品,但是代码中j不可能取到2,这里发生了错误。

更好的办法就是当j+t[i]>ti时一律将j+t[i]视为ti,k+a[i]视为ai。

for (i=1;i<=m;i++)
{
    for (j=ti;j>=0;j--)
    {
        for (k=ai;k>=0;k--)
        {
            x=j+t[i];if (x>ti) x=ti;
            y=k+a[i];if (y>ai) y=ai;
            if (dp[x][y]>dp[j][k]+w[i])
            {
                dp[x][y]=dp[j][k]+w[i];
            }
        }
    }
}

完整代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<queue>
#include<string>
#include<sstream>
#define eps 1e-9
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define MAXN 1005
#define MAXM 40005
#define INF 0x3fffffff
using namespace std;
typedef long long LL;
int i,j,k,n,m,x,y,T,ans,big,cas,num,len;
bool flag;

int ti,ai,t[1005],a[1005],w[1005],dp[1005][1005];

int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&ti,&ai);
        scanf("%d",&m);
        for (i=1;i<=m;i++)
        {
            scanf("%d%d%d",&t[i],&a[i],&w[i]);
        }

        memset(dp,0x2f,sizeof(dp));
        dp[0][0]=0;

        ans=INF;

        for (i=1;i<=m;i++)
        {
            for (j=ti;j>=0;j--)
            {
                for (k=ai;k>=0;k--)
                {
                    x=j+t[i];
                    y=k+a[i];
                    if (x>ti) x=ti;
                    if (y>ai) y=ai;
                    if (dp[x][y]>dp[j][k]+w[i])
                    {
                        dp[x][y]=dp[j][k]+w[i];
                    }
                }
            }
        }
        printf("%d\n",dp[ti][ai]);
    }
    return 0;
}
时间: 2024-10-14 10:24:00

SPOJ 181 - Scuba diver 二维背包的相关文章

二维背包初步

问题 二维费用的背包问题是指:对于每件物品,具有两种不同的费用:选择这件物品必须同时付出这两种代价:对于每种代价都有一个可付出的最大值(背包容量). 问怎样选择物品可以得到最大的价值. 设这两种代价分别为代价1和代价2,第i件物品所需的两种代价分别为a[i]和b[i].两种代价可付出的最大值(两种背包容量)分别为V和U.物品的价值为c[i]. 算法 费用加了一维,只需状态也加一维即可. 设f[i][v][u]表示前i件物品付出两种代价分别为v和u时可获得的最大价值. 状态转移方程就是:f [i]

B 二维背包+完全背包 Hdu2159

<span style="color:#3333ff;">/* ------------------------------------------------------------------------------------------------ author : Grant Yuan time : 2014.7.19 aldorithm: 二维背包+完全背包 ----------------------------------------------------

hdu2159 FATE 二维背包

感觉用背包去想反而麻烦..就是一个递推 #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #define inf 0x3f3f3f3f #define ll __int64 us

二维背包(钟神想要的)(不是DP)

[问题描述] 背包是个好东西,希望我也有.给你一个二维的背包,它的体积是? × ?.现在你有一些大小为1× 2和1×3的物品,每个物品有自己的价值.你希望往背包里面装一些物品,使得它们的价值和最大,问最大的价值和是多少. [输入格式] 第一行一个整数?代表该测试点的数据组数.对于每组数据,第一行有四个整数?,?,? 1 ,? 2 ,其中? 1 ,? 2 分别代表大小为1× 2和大小为1 × 3的物品个数.1 × 2 接下来一行有? 2 个数代表每个1 × 3物品的价值. [输出格式] 对于每组询

HDU 2159FATE(二维背包)

题目地址:HDU 2159 二维的背包,刚开始用的一维,老感觉哪里不对,有两个制约因素.于是就改成了二维的,就过了.. 代码如下: #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <cmath> #include <sta

hdu 2660 Accepted Necklace (二维背包)

Accepted Necklace Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2530    Accepted Submission(s): 999 Problem Description I have N precious stones, and plan to use K of them to make a necklace f

hdu2159FATE(二维背包)

FATE Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3051    Accepted Submission(s): 1297 http://acm.hdu.edu.cn/showproblem.php?pid=2159 Problem Description 最近xhd正在玩一款叫做FATE的游戏,为了得到极品装备,xhd在不停的

D - FATE HDU-2159 FATE 二维背包

D - FATE Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description 最近xhd正在玩一款叫做FATE的游戏,为了得到极品装备,xhd在不停的杀怪做任务.久而久之xhd开始对杀怪产生的厌恶感,但又不得不通过杀怪来升完这最后一级.现在的问题是,xhd升掉最后一级还需n的经验值,xhd还留有m的忍耐度,每杀一个怪xhd会得到相应的经验,并减掉相应的

poj1015 01二维背包

/* 给定辩控双方给每个人的打分p[i],d[i], dp[j][k]表示前i个人有j个被选定,选定的人的辩控双方打分差之和是k,此状态下的最大辩控双方和 按01背包做,体积一维是1,体积二维是辩控双方打分差,价值是辩控双方打分和 要求体积一维不得超过m,体积二维在体积一维=m的情况下最小 状态转移方程:dp[j][k]=max(dp[j][k],dp[j-1][k-(a[i]-b[i])]+a[i]+b[i]) */ #include<iostream> #include<cstrin