问题描述:

给定 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;
}