學校的算法實驗,用回溯和遞歸求解01揹包問題。覺得回溯思路不適合解01揹包問題,因爲01揹包問題中摻雜了兩個變量:揹包容量和攜帶的價值(價值比較出最大價值),但畢竟是學校實驗,還是得做啊。
我的思路是,設一個數組,長度爲物品的數量。數組爲賦值爲0,則表示當前物品不取;賦值爲1,則取。然後對每一位遍歷,最後比較。用動態做最省事。
回溯代碼:
#include <stdio.h>
#include <malloc.h>
#define M 5
int *choice,*saved;
int maxV = -1;
void KNAPSACK(int *v,int *s,int C,int n);
int main(void)
{
int s[M] = {3,5,7,8,9},v[M] = {4,6,7,9,10},C = 11;
int i=0,sum=0;
KNAPSACK(v,s,C,M);
printf("選擇");
for(i=0;i<M;i++)
{
if(saved[i])
{
printf("第%d項,",i+1);
sum+=s[i];
}
}
printf("物品放入揹包,");
printf("物品總體積爲:%d,總價值爲%d.",sum,maxV);
return 0;
}
//v數組價值,s數組體積,C揹包容量,n數量
void KNAPSACK(int *v,int *s,int C,int n)
{
choice = (int*)malloc(sizeof(int)*(n+1));
saved = (int*)malloc(sizeof(int)*(n+1));
int flag = 0;
int i=0,j=0,k=0;
int value=0,bag=0;
for(i=0;i<n;i++)
choice[i]=-1,saved[i]=-1;
while(k>=0)
{
while(choice[k]<1) //篩選每一個物品,兩種可能,取或者不取分別對應0/1
{
choice[k]++;
if(k==n)
{
value=0,bag=0;
for(i=0;i<n;i++)
{
if(choice[i])
{
bag+=s[i];
value+=v[i];
}
}
if(maxV<value&&bag<=C)
{
maxV = value;
for(i=0;i<n;i++) saved[i] = choice[i];
}
break;
}
else k++;
}
choice[k] = -1;
k--;
}
}
遞歸代碼:
#include <stdio.h>
#include <malloc.h>
#define M 5
int *choice,*saved;
int maxV = -1;
void KNAPSACK(int *v,int *s,int C,int cur);
int main(void)
{
int s[M] = {3,5,7,8,9},v[M] = {4,6,7,9,10},C = 11;
choice = (int*)malloc(sizeof(int)*M);
saved = (int*)malloc(sizeof(int)*M);
int i=0,sum=0;
KNAPSACK(v,s,C,0);
printf("選擇");
for(i=0;i<M;i++)
{
if(saved[i])
{
printf("第%d項,",i+1);
sum+=s[i];
}
}
printf("物品放入揹包,");
printf("物品總體積爲:%d,總價值爲%d.",sum,maxV);
return 0;
}
//v數組價值,s數組體積,C揹包容量,cur當前位
void KNAPSACK(int *v,int *s,int C,int cur)
{
if(cur==M-1)
{
int value=0,bag=0,i=0;
for(i=0;i<M;i++)
{
if(choice[i])
{
bag+=s[i];
value+=v[i];
}
}
if(maxV<value&&bag<=C)
{
maxV = value;
for(i=0;i<M;i++) saved[i] = choice[i];
}
return;
}
else
{
choice[cur] = 0;
KNAPSACK(v,s,C,cur+1);
choice[cur] = 1;
KNAPSACK(v,s,C,cur+1);
}
}