我一直试图在SPOJ解决http://www.spoj.com/problems/SCUBADIV/问题。我想出了一个递归的DP解决方案。
我正在使用带有三维阵列的背包方法来存储气瓶数量,所需的氧气重量和氮气重量。在每个递归步骤中,我检查尚未填充的氧气和氮气的量。如果它是负数,那就好于零。
#include<bits/stdc++.h>
using namespace std;
#define inf 99999999
int n;
vector<int> o;
vector<int> ni;
vector<int> w;
int ow;
int nw;
int knapsack(int n,int ow,int nw); // n - number of cylinders,ow-wt. of oxygen
// nw-wt. of nitogen.
int main(){
int t;
scanf("%d",&t);
while(t--){
int i;
scanf("%d %d",&ow,&nw);
scanf("%d",&n);
o.resize(n);
ni.resize(n);
w.resize(n);
for(i=0;i<n;i++)
scanf("%d%d%d",&o[i],&ni[i],&w[i]); // o[i] storing wt. of oxygen cylinders
int res = knapsack(n,ow,nw); //ni[i] storing wt. of nitrogen cylinders
printf("%d",res);
}
return 0;
}
int knapsack(int n,int ow,int nw){
int dp[n+1][ow+1][nw+1];
memset(dp,inf,sizeof (dp)); //setting value of array to inf to get minimum weight
int i;
for(i=0;i<n;i++)
dp[i][0][0]=0;
if(dp[n][ow][nw]!= inf)
return dp[n][ow][nw];
else if (ow - o[n-1]>=0 && nw - ni[n-1]>=0)
return dp[n][ow][nw]= min(knapsack(n-1,ow,nw),w[n-1]+knapsack(n-1,ow-o[n-1],nw-ni[n-1]));
else if(ow -o[n-1]<0 && nw - ni[n-1] >=0)
return dp[n][ow][nw]=min(knapsack(n-1,0,nw),w[n-1]+knapsack(n-1,0,nw-ni[n-1]));
else if(ow-o[n-1]>=0 && nw-ni[n-1]<0)
return dp[n][ow][nw]=min(knapsack(n-1,ow,0),w[n-1]+knapsack(n-1,ow-o[n-1],0));
else if(ow-o[n-1]<0 && nw-ni[n-1]<0)
return dp[n][ow][nw]= knapsack(n-1,0,0);
}
此代码未给出所需的结果(它给出了-1)。方法是否正确?
答案 0 :(得分:1)
此代码存在问题:
int dp[n+1][ow+1][nw+1];
memset(dp,inf,sizeof (dp));
memset()
函数设置字节模式,而不是值。由于inf
是一个大于一个字节的值,因此它基本上执行inf % 256
并将dp[][][]
中的所有字节初始化为该值。 dp[][][]
属于基类型int
,这进一步复杂化,因此设置为相同字节值的4个字节是意外的。
如果inf
的值为99999999
,则字节值将为0xff,因此int
中的所有dp[][][]
都将设置为-1
我不知道这是否是预期的,但看起来这可能是个错误。
答案 1 :(得分:1)
设M(x,O,N)是通过仅从气缸1到x中选择将提供O升氧气和N升氮气的气缸的最小重量。设O(x),N(x)和W(x)分别是第x个气缸中可用的氧气和氮气的量以及气缸的重量。然后我们要么选择使用第x个圆柱,要么我们不选择:
M(x, O, N) = min( W(x) + M(x - 1, O - O(x), N - N(x)), M(x - 1, O, N) )
当我们根本没有气瓶时会发生基本情况。
M(0, O, N) = 0 if O <= 0 and N <= 0, infinity otherwise
我不会阅读您的未格式化,加密编写的代码,以确定它是否正确实现了这一点。我会说memset
只能用于将 bytes 设置为给定值。你的电话没有按你的想法行事。此外,如果执行到达if
链的末尾,则递归过程将返回垃圾。
手工制作一个小例子。在调试器中或插入printf
运行代码以显示正在进行的操作。弄清楚它的实际执行偏离你的手计算。
答案 2 :(得分:0)
是的,可以通过递归方法解决此问题,但这不是如何做到的。代码存在多个问题,显然&#39;它会返回-1。我将尝试回答的问题是:告诉我这段代码有些问题。
dp
之类的变量名称掩盖了代码的含义。给他们有意义的名字!memset
函数填充字节,在本例中为-1。使用循环初始化整数。if
语句只能返回0或-1(或修复init后的inf)。因为它是其他代码将不会被执行。dp
无效,因为它位于自动存储中(在堆栈上)。if
语句链。解释一下。else
因此功能可能会失效。最好重写,调试,如果仍然没有工作,我们可以阅读。