递归DP方法
SPOJ SCUBADIV - Recursive DP Approach
我一直在尝试解决http://www.spoj.com/problems/SCUBADIV/问题在SPOJ。我已经提出了一个递归的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)。方法正确吗?
这段代码有问题:
int dp[n+1][ow+1][nw+1];
memset(dp,inf,sizeof (dp));
memset()
函数设置一个字节模式,而不是一个值。由于inf
是一个大于一个字节的值,它实际上是执行inf % 256
并将dp[][][]
中的所有字节初始化为该值。由于dp[][][]
的基本类型是int
,所以将4个字节设置为相同的字节值是不可预料的。
在inf
的情况下,99999999
的字节值将是0xff,因此dp[][][]
中的所有int
将被设置为-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
只能用于将字节设置为给定值。你的决定不像你想的那样。此外,如果执行到if
链的末尾,递归过程将返回垃圾。
手工编写一个小示例。在调试器中运行代码或插入printf
s以显示正在发生的事情。找出它的实际执行与你的手工计算有什么不同
是的,可以用递归方法解决这个问题,但这不是怎么做的。代码有多个问题,"显然"它将返回-1。我要回答的问题是:告诉我这段代码的一些错误之处。
- 像
dp
这样的变量名模糊了代码的含义。给他们起个有意义的名字! - 不要调整矢量的大小并读入指针。读取值并将其压入向量。
- 打印出数据,以确保读取正确。
-
memset
函数填充字节,在本例中为-1。使用循环初始化int。 - 第一个
if
语句只能返回0或-1(或inf一旦你修复了init)。因为它是其他代码将不会被执行。 - 给
dp
赋值是无效的,因为它是自动存储的(在堆栈上)。 - 我不理解
if
语句链。解释它们。 - 没有
else
,所以函数可以掉到末尾。
最好重写,调试,如果它仍然不能工作,返回一些我们可以读的
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 对于 spoj 的问题 TRT(对待奶牛)的 dp 的最佳方法是什么?
- 为什么我的 DP 方法不适用于某些输入
- 有没有一种方法可以优化这个DP程序中的空间
- 递归DP方法
- DP方法,用于生成字符串回文时应添加的最小字符数