/*0-1背包回溯法实现*/
#include <stdio.h>
#include <conio.h>
int n; //物品数量
double c; //背包容量
double v[100]; //各个物品的价值
double w[100]; //各个物品的重量
double cw = 0.0; //当前背包重量
double cp = 0.0; //当前背包中物品价值
double bestp = 0.0; //当前最优价值
double perp[100]; //单位物品价值排序后
int order[100]; //物品编号
int put[100]; //设置是否装入
/*按单位价值排序*/
void knapsack()
{
int i,j;
int temporder = 0;
double temp = 0.0;
for(i=1;i<=n;i++)
perp[i]=v[i]/w[i];
for(i=1;i<=n-1;i++)
{
for(j=i+1;j<=n;j++)
if(perp[i]<perp[j]) //冒泡排序perp[],order[],sortv[],sortw[]
{
temp = perp[i];
perp[i]=perp[i];
perp[j]=temp;
temporder=order[i];
order[i]=order[j];
order[j]=temporder;
temp = v[i];
v[i]=v[j];
v[j]=temp;
temp=w[i];
w[i]=w[j];
w[j]=temp;
}
}
}
/*回溯函数*/
void backtrack(int i)
{
double bound(int i);
if(i>n)
{
bestp = cp;
return;
}
if(cw+w[i]<=c)
{
cw+=w[i];
cp+=v[i];
put[i]=1;
backtrack(i+1);
cw-=w[i];
cp-=v[i];
}
if(bound(i+1)>bestp) //符合条件搜索右子数
backtrack(i+1);
}
/*计算上界函数*/
double bound(int i)
{
double leftw= c-cw;
double b = cp;
while(i<=n&&w[i]<=leftw)
{
leftw-=w[i];
b+=v[i];
i++;
}
if(i<=n)
b+=v[i]/w[i]*leftw;
return b;
}
int main()
{
int i;
printf("请输入物品的数量和容量:");
scanf("%d %lf",&n,&c);
printf("请输入物品的重量和价值:\n");
for(i=1;i<=n;i++)
{
printf("第%d个物品的重量:",i);
scanf("%lf",&w[i]);
printf("价值是:");
scanf("%lf",&v[i]);
order[i]=i;
}
knapsack();
backtrack(1);
printf("最优价值为:%lf\n",bestp);
printf("需要装入的物品编号是:");
for(i=1;i<=n;i++)
{
if(put[i]==1){
printf("%d ",order[i]);
}
}
printf("\n");
return 0;
}