问题描述:
给定 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; }