01背包问题
背包问题博大精深,这里讲的应该是最简单的一种。
问题描述
假设有n件质量分配为w1,w2,…,wn的物品和一个最多能装载总质量为maxW的背包,能否从这n件物品中选择若干件物品装入背包,使得被选物品的总质量“恰好”等于背包所能装载的最大质量,即wi1+wi2+…+wik=maxW。若能,则背包问题有解,否则无解。
算法思想
首先将n件物品排成一列,依次选取;若装入某件物品后,背包内物品的总质量不超过背包最大装载质量时,则装入(进栈);否则放弃这件物品的选择,选择下一件物品试探,直至装入的物品总和正好是背包的最大转载质量为止。这时我们称背包装满。
若装入若干物品的背包没有满,而且又无其他物品可以选入背包,说明已装入背包的物品中有不合格者,需从背包中取出最后装入的物品(退栈),然后在未装入的物品中挑选,重复此过程,直至装满背包(有解),或无物品可选(无解)为止。
具体实现
注释部分仅用于打印执行步骤
这里对于出栈入栈的处理比较简单,仅仅通过下标的变化来表示
#include<stdio.h>
#define MAXSIZE 5 //可放入背包的物品数量
int knapsack(int n , int maxW , int *weight);
void main()
{
int maxW = 13; //背包所能容纳的数量
int weight[MAXSIZE + 1] = {0,2,5,7,1,8}; //一组物品重量,下标从1开始
int n = MAXSIZE;
if(knapsack(n , maxW , weight) == 1)
{
printf("问题有解\n\n");
}
else
{
printf("问题无解\n\n");
}
}
int knapsack(int n , int maxW , int *weight)
{
int stack[MAXSIZE + 1];
int top = 0 , i = 1;
while(maxW > 0 && i <= n)
{
//printf("top=%d , i=%d , maxW=%d\n" , top , i , maxW);
if(maxW - weight[i] >= 0 && i <= n)
{
top++;
stack[top] = i;
maxW -= weight[i];
}
if(maxW == 0) //问题有解,返回1
{
/*
int j = 1;
printf("top=%d , i=%d , maxW=%d\n" , top , j , maxW);
while(j <= top)
{
printf("stack[%d]=%d\n" , j , stack[j++]);
}
*/
return 1;
}
if(top == MAXSIZE) //如果将全部物品都放入背包,背包仍未放满,则问题无解,返回0
{
return 0;
}
else
{
if(i == n && top > 0) //装入背包的物品中有不合格者
{
i = stack[top];
top--;
maxW += weight[i];
if(i == n) //需要换最底部的物品时就应该退两次栈
{
i = stack[top];
top--;
maxW += weight[i];
}
}
}
i++;
}
return 0;
}
测试结果:
:)