/**
簡單揹包問題
問題定義:
有一個揹包重量是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;
}
揹包問題的遞歸和非遞歸的解法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.