tcktbar13122

背包问题使用顺序栈的方法解决。

 

1.问题描述

有一个背包,能盛放的物品总重量为t,现有n件物品,其重量分别为w1、w2、...、wn,问能否从这n件物品中选择若干件装满这个背包?

 

2.问题分析

装包过程是将n件物品排成一列,依次选取;若选取的物品装入后,背包内物品的总重量不超过背包总重量时,则装入;否则放弃这件物品的选择,选择下一件物品试探,但如果在剩余的物品中找不到“合适”的物品,则说明“刚刚”装入背包的物品“不合适”,应该将其取出,继续再从未装入的物品中选取。重复此过程,直至装满背包为止。

背包中物品的装入与取出具有“后进先出”的特点,采用顺序栈来表示背包中的物品。

 

3.算法描述

(1)依次选取每一个物品i,若t>w[i],表示该物品可选,则将下标i进栈;同时,从t中减去该物品的重量w[i]。

(2)当t等于0时,背包刚好装满。

(3)当无物品可选时,需退栈。退栈时,要将相应物品的重量加到t中。

 

流程图如下:

#define MAXSIZE 50i
#include<stdio.h>

typedef struct node{
    int data[MAXSIZE];
    int top;
}Node;

/*函数声明*/
void InitStack(Node *p);    //初始化栈(置空栈)
void PushStack(Node *p, int n);    //进栈
int PopStack(Node *p);    //退栈
int IsEmpty(Node *p);    //判栈空
void Bag(int things, int *weight, int bag);    //背包函数

/*主函数*/
int main(void){
    int things,weight[MAXSIZE],bag,s,i;
    printf("Please enter the number of the things:");
    scanf("%d",&things);
    printf("\nPlease enter their weight in order:");
    for(i=0,s=0;i<things;i++){
        scanf("%d",&weight[i]);
        s=s+weight[i];
    }
    printf("\nTheir weight in total is %d.",s);
    printf("\nPlease enter the weight that the bag can contain(under %d):",s);
    scanf("%d",&bag);
    Bag(things, weight, bag);
}

/*函数1*/
void InitStack(Node *p){
    p->top=-1;
}

/*函数2*/
void PushStack(Node *p, int w){
    p->data[++p->top]=w;
}

/*函数3*/
int PopStack(Node *p){
    int v;
    v=p->data[p->top--];
    return v;
}

/*函数4*/
int IsEmpty(Node *p){
    return (p->top==-1);
}

/*背包函数*/
void Bag(int things, int *weight, int bag){
    Node Stack;
    int i=0,j=0,k;
    InitStack(&Stack);  //初始化栈
    do{
        while(i<things && bag>0){    //装包过程
            if(bag>=weight[i]){
                PushStack(&Stack, i);
                bag=bag-weight[i];
            }
            i++;
        }
        if(bag==0){
            j++;
            printf("OK solution No.%d:",j);
            for(k=0;k<=Stack.top;k++){
                printf("%d ",weight[Stack.data[k]]);
            }
            printf("\n");
        }
        i=PopStack(&Stack);    //标记1     让i记录下栈顶的值    //从背包中取出最后装进的物品
        bag=bag+weight[i];
        i++;            //标记2  下次循环开始时从这次的最后一个物品的下一个物品开始拿
    }while(!IsEmpty(&Stack)||i<things);
}

 

data记录的是被放入包里的物品的下标,top指示栈顶的位置。

标记1和标记2让i在每次循环开始的时候能将第一个放入包里的东西往后移一个,也就是第一轮一开始放进包里的是第一个物品,如果第二轮还是的话,之后的步骤就和第一轮一模一样了,所以要往后移一个,第二轮要从第二个物品开始放。以此类推,最后一轮只把最后一个物品放入包里,不满足条件(包内剩余空间不等于0)的话,下一轮i就大于物品数量(不满足大循环条件)了,退栈以后栈空(因为这一轮只放了一个物品进包里),于是跳出大循环,结束程序。

最重要的还是用i记录了栈顶的值。还有大循环的条件:栈非空,这里十分巧妙,它防止了在某一轮(不是最后一轮)试过最后一个物品能不能放进背包之后,这时候i大于物品数量(因为i在小循环那里加了1),如果没有栈非空的条件的话,就跳出大循环了。这样的情况,就是只能放第一轮物品。我一开始就有这样的疑惑:为什么这个程序可以进行许多轮并输出正确答案,一开始我以为它只能进行第一轮。

分类:

技术点:

相关文章:

  • 2022-12-23
  • 2021-09-30
  • 2021-12-24
  • 2019-03-14
  • 2021-11-16
  • 2021-11-06
  • 2022-12-23
猜你喜欢
  • 2021-05-16
  • 2022-12-23
  • 2022-12-23
  • 2022-01-03
  • 2022-12-23
  • 2022-12-23
  • 2021-12-15
相关资源
相似解决方案