问题描述:
给定 n 个物品和一个容量为 C 的背包,请 给出物品装入背包的方案,使得背包中物品的总价值 M 最大,并 满足:
• 每个物品 I 的重量为 w i ,价值为 v i 。
• 每个物品可拆分,背包中物品的总重量不能超过容量 C 。
实验要求:
程序实现要求:
• 1 )先写排序算法 Rank() ,再写贪心算法 Greedy() 。
• 2 )两个步骤需要单独定义在程序里,不写在主函数里。
贪心算法解背包问题的基本步骤:
• 1 )计算每种物品单位重量的价值 V i / W i
• 2 )依贪心选择策略,将尽可能多的 单位重量价值最高 的物品装入背包。
• 3 )若将这种物品全部装入背包后,背包内的物品总重量未超过 C ,则选择单位重量价值次高的物品并尽可能多地装入背包。
• 4 )依此策略一直进行下去,直到背包装满为止。
#include<stdio.h>
#define N 100
int v[N];//价值
int w[N];//重量
float fw[N];//防止比例小数,转换重量用
int record[N];//记录排序后每个数字原来位置,从0开始,对应vw数组
int C;//给出背包容量
int n;//物品个数
int M=0;//背包容量为C时最大价值
int SurplusC;//剩余背包重量
void swap(int *x,int *y){//交换函数
int temp;
temp=*x;
*x=*y;
*y=temp;
}
void Rank(float s[], int l, int r){//用快速排序从大到小排序
if (l < r){
//swap(&s[l], &s[(l + r) / 2]);//将中间的这个数和第一个数交换,可提高效率
int i = l, j = r;//左边从第一个数开始,右边从最后一个数开始
float x = s[l];
while (i < j){
while(i < j && s[j] <= x) // 从右向左找第一个大于x的数
j--;
if(i < j){
s[i] = s[j];
swap(&record[i],&record[j]);//记录交换信息
i++;
}
while(i < j && s[i] > x) // 从左向右找第一个小于等于x的数
i++;
if(i < j){
s[j] = s[i];
swap(&record[j],&record[i]);//记录交换信息
j--;
}
}
s[i] = x;//实现交换
Rank(s, l, i - 1); // 递归调用
Rank(s, i + 1, r);
}
}
void Greedy(){//贪心算法
float vw[N];//记录价值与重量比,保留小数
int i,k=0;
for(i=0;i<n;i++)//把整形重量转换为浮点型重量
fw[i]=w[i];
for(i=0;i<n;i++)//计算比例
vw[i]=v[i]/fw[i];
Rank(vw, 0, n-1);//把比例排序
SurplusC=C;//剩余重量赋初值
while(SurplusC>0){//还有剩余空间
if(SurplusC>=w[record[k]]){//够装的下下一个物品
M+=v[record[k]];
SurplusC-=w[record[k]];
k++;
}
else{//不够装得下下一个物品
v[record[k]]=(int)(SurplusC*vw[record[k]]);//直接修改价值和重量数组,所以原数组被破坏了
w[record[k]]=SurplusC;
M+=v[record[k]];
SurplusC-=w[record[k]];
}
}
}
void IO(){
int i,k=0,num[20];
FILE *ifp,*ofp;
ifp=fopen("input.txt","r");
fscanf(ifp,"%d\r\n",&C);///r/n实现记事本换行/r回车符/n换行
while(!feof(ifp)){
fscanf(ifp,"%d\t%d\t%d\r\n",&num,&w[k],&v[k]);
k++;
}
fclose(ifp);
n=k;//单独给n赋值
printf("文件数据已成功读取...\n");
for(i=0;i<n;i++)//初始化记录数组,不知道为什么放在主函数就不执行了
record[i]=i;
//for(i=0;i<n;i++)
// printf("%d ",record[i]);
//printf("\n");
Greedy();
ofp=fopen("output.txt","wb");
fprintf(ofp,"%d\r\n",M);
for(i=0;i<n;i++)
{
fprintf(ofp,"%d\t%d\t%d\r\n",i,w[i],v[i]);
}
fclose(ofp);
printf("结果已输出到本目录文件\"output.txt\"中...\n");
}
int main(){
/*
int i;
for(i=0;i<n;i++)//初始化记录数组,不知道为什么放在主函数就不执行了
record[i]=i;
for(i=0;i<n;i++)
printf("%d ",record[i]);
printf("\n");
*/
IO();
return 0;
}