背包问题的递归和非递归算法

/**
简单背包问题
问题定义:
有一个背包重量是S,有n件物品,重量分别是W0,W1...Wn-1
问能否从这n件物品中选择若干件放入背包中使其重量之和正好为S
*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
const int maxsize=100;
int n,S;//n是有多少中物品,S是要凑足的重量
bool visit[maxsize];//标记是否被访问过,别访问过标记为1,没有访问过为0
int w[maxsize];//记录每一种物品的重量
int q[maxsize];//相当于一个栈,存储被访问过的物品的编号
int beibao()
{
    int top=-1,begin=0,sum=0;
    int i;
    while(top!=-2)
    {
        //从第一个物品开始循环
        for(i=begin;i<n;i++)
        {
            //如果没有被访问过,并且加上重量之和小于S
            if(!visit[i] && w[i]+sum<=S)
            {
                sum+=w[i];//在sum上加上当前物品的重量
                q[++top]=i;//把物品的编号存入q[]中
                begin=0;//从头开始访问
                visit[i]=1;//该结点访问过标记
                if(sum==S) return top;//如果成功,返回top,top为数组元素的个数,有所有物品的编号
                break;
            }
        }
        //如果检索到最后,也就是说栈顶前面的物品都不符合条件
        //因此可能栈内的元素有问题,所以弹出栈顶元素,不把栈顶元素计算在内
        if(i==n)
        {
            visit[q[top]]=0;//把栈顶元素定义成未访问
            sum-=w[q[top]];//从和中减去站定物品编号的重量
            begin=q[top]+1;//从栈顶元素的下一个物品开始检索
            //cout<<"------"<<begin<<endl;
            top--;//栈递减一个单位
        }
    }
}
//背包问题递归版本
/**
解释:其选择只有两种可能,选择一组物品中包含Wn-1 ,此时knap(s,n)的解就是knap(s - Wn-1,n-1)的解
如果选择的物品中不包括Wn-1,这样knap(s,n)的解就是knap(s,n-1)的解
knap(s,n) = true, 当 s=0时
            false ,当s < 0 或者 s > 0 且 n < 1
            knap(s - Wn-1,n-1) || knap(s,n-1) 当s>0且n>=1
*/
bool knap(int s,int n)
{
    if(s == 0) return true;//递归出口 在s恰好为0时 递归结束
    if(s < 0 || (s > 0&&n < 0)) return false;//或者s小于0 n 小于0时
    if(knap(s - w[n - 1],n - 1))
    {
        cout<<w[n - 1];
        return true;
    }else return knap(s,n - 1);
}
int main()
{
    cin>>n>>S;
    for(int i=0;i<n;i++)
    {
        cin>>w[i];
        visit[i]=0;
    }
    int t=beibao();
    knap(S,n);
    if(t!=-1)
    {
        for(int i=0;i<=t;i++)
            cout<<w[q[i]]<<" ";
        cout<<endl;
    }
    else cout<<-1<<endl;
}

猜你喜欢

转载自blog.csdn.net/zhao2018/article/details/80659539