根据维基百科和我经历过的其他资料,你需要矩阵m[n][W]
; n
- 项目数量和W
- 背包总容量。这个矩阵变得非常大,有时候太大了,无法在C程序中处理它。我知道动态编程是基于节省内存的时间,但是,还有什么解决方案可以节省时间和内存吗?
// Input:
// Values (stored in array v)
// Weights (stored in array w)
// Number of distinct items (n)
// Knapsack capacity (W)
for j from 0 to W do
m[0, j] := 0
end for
for i from 1 to n do
for j from 0 to W do
if w[i] <= j then
m[i, j] := max(m[i-1, j], m[i-1, j-w[i]] + v[i])
else
m[i, j] := m[i-1, j]
end if
end for
end for
让我们说,W = 123456789,n = 100.在这种情况下,我们得到了非常大的矩阵m [100] [123456789]。我正在考虑如何实现这一点,但我最好只想保存用一位(0/1)选择的项目。这可能吗?或者还有其他方法可以解决这个问题吗?
int32 -> 32 * 123456789 * 100 bits
one_bit -> 1 * 123456789 * 100 bits
我希望这不是一个愚蠢的问题,谢谢你的努力。
编辑 - 正在使用的C代码:
long int i, j;
long int *m[2];
m[0] = (long int *) malloc(sizeof(long int)*(W+1));
m[1] = (long int *) malloc(sizeof(long int)*(W+1));
for(i = 0; i <= W; i++){
m[0][i] = 0;
}
int read = 0;
int write = 1;
int tmp;
long int percent = (W+1)*(n)/100;
long int counter = 0;
for(i = 1; i <= n; i++){
for(j = 0; j <= W; j++){
if(w[i-1] <= j){
m[write][j] = max(m[read][j],(v[i-1]) + m[read][j-(w[i-1])]);
}else{
m[write][j] = m[read][j];
}
counter++;
if(counter == percent){
printf("."); //printing dot (.) for each percent
fflush(stdout);
counter = 0;
}
}
tmp = read;
read = write;
write = tmp;
}
printf("\n%ld\n", m[read][W]);
free(m[0]);
free(m[1]);
答案 0 :(得分:4)
使用O(W)
空格可以解决背包问题。
在迭代的每一步,您只需要2行 - 数组的当前状态m[i]
和m[i + 1]
。
current = 1
int m[2][W]
set NONE for all elements of m # that means we are not able to process this state
m[0][0] = 0 # this is our start point, initially empty knapsack
FOR i in [1..n] do
next = 3 - current; /// just use 1 or 2 based on the current index
for j in [0...W] do
m[next][j] = m[current][j]
FOR j in [w[i]..W] do
if m[current][j - w[i]] is not NONE then # process only reachable positions
m[next][j] = max(m[next][j], m[current][j - w[i]] + v[i]);
current = next; /// swap current state and the produced one
也可以只使用1个阵列。这是伪代码
FOR i in [1..n] do
FOR j in [w[i]..W] do
m[j] = max(m[j], m[j - w[i]] + v[i]);
答案 1 :(得分:3)
您可以通过以下观察将空间使用从m [100] [123456789]减少到m [2] [123456789]:
看看代码的这一部分,你只需要参考矩阵i和i的两行
if w[i] <= j then
m[i, j] := max(m[i-1, j], m[i-1, j-w[i]] + v[i])
else
m[i, j] := m[i-1, j]
end if
你可以使用这个技巧:
int current = 1;
//.........
if w[i] <= j then
m[current, j] := max(m[1 - current, j], m[1 - current, j-w[i]] + v[i])
else
m[i, j] := m[1 - current, j]
end if
current = 1 - current;