问题描述:
给定
n
个物品和一个容量为
C
的背包,请
给出物品装入背包的方案,使得背包中物品的总价值
M
最大,并
满足: •
每个物品
I
的重量为
w
i
,价值为
v
i
。 •
每个物品不可拆分,要么完整装入背包,要么不在背包里。 •
背包中物品的总重量不能超过容量
C
。
实验要求:
#include<stdio.h>
#define N 100
int v[N];//价值
int w[N];//重量
int t[N];//记录拿不拿
int temp[N];
float fw[N];//防止比例小数,转换重量用
//int record[N];//记录排序后每个数字原来位置,从0开始,对应vw数组
int C;//给出背包容量
int n;//物品个数
//int M = 0;//背包容量为C时最大价值
//int SurplusC;//剩余背包重量
int cw=0;//当前重量
int cv=0;//当前价值
int bestv;//当前最优价值
float tw[N],tv[N],wv[N];
void swap(float *x, float *y) {//交换函数
float 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(&tw[i], &tw[j]);//交换重量
swap(&tv[i], &tv[j]);//交换价值
i++;
}
while (i < j && s[i] > x) // 从左向右找第一个小于等于x的数
i++;
if (i < j) {
s[j] = s[i];
swap(&tw[j], &tw[i]);//交换重量
swap(&tw[j], &tw[i]);//交换价值
j--;
}
}
s[i] = x;//实现交换
Rank(s, l, i - 1); // 递归调用
Rank(s, i + 1, r);
}
}
int bound(int i) {//计算上界
int j;
int cleft = C - cw;//剩余容量
int bound = cv;
for(j=0;j<n;j++){
tw[j]=w[j];
tv[j]=v[j];
wv[j]=v[j]/w[j];
}
Rank(wv,i,n-1);
//以物品单位重量价值递减序装入物品,w[i]已排好序
while (i < n && w[i] <= cleft) {
cleft -= w[i];
bound += v[i];
i++;
}
//装满背包
if (i < n)
bound += v[i] / w[i] * cleft;
return bound;
}
void backtrack(int i) {//回溯算法
//搜索第i层结点
int j;
if (i >= n) {//到达叶结点
if(cv>bestv){
bestv = cv;
for(j=0;j<n;j++)
t[j]=temp[j];
}
return;
}
//搜索子树
if (cw + w[i] <= C) {//进入左子树
cw += w[i];
cv += v[i];
temp[i] = 1;
backtrack(i + 1);
cw -= w[i];
cv -= v[i];
}
if (bound(i + 1) > bestv) {//进入右子树
temp[i] = 0;
backtrack(i + 1);
}
}
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");
backtrack(0);
ofp = fopen("output.txt", "wb");
fprintf(ofp, "%d\r\n", bestv);
for (i = 0; i<n; i++)
{
fprintf(ofp, "%d\t%d\t%d\r\n", (i+1), t[i], v[i]);
}
fclose(ofp);
printf("结果已输出到本目录文件\"output.txt\"中...\n");
}
int main() {
IO();
return 0;
}
插入图片应该不利于检索推广吧,不过谁叫自己懒呢。
在和老师沟通后得知企业普遍用传递参数而不是用全局变量,自己指针理解程度不高没敢用传递参数,所以写成了这个样子,还是姚改进的,也挺感谢算法胡老师的,是真的厉害,没有她,或许也就没有了这个算法的系列了,一共五篇,应该还有最后一篇这个学期就结束了,也因为这个让自己不畏惧算法,不讨厌算法。自己的大多数算法都没有看课本给的代码,一来是看不懂,二来也是自己上课听了,知道原理是有写的逻辑的,虽然可能写的不好,但至少可以完成罢了。每次听室友说这个多难多难,他请教班里学霸也用了一天就感到很诧异,不过对于写这个系列博客的初衷而言,结果是一样的,毕竟自己学了就忘,记忆力实在差的可以,只能以这样的方式表示自己做过,并且帮助一下后来人,如果有人自己写不出来,看看自己代码有了启发也是极好的。
当然还是不要交差型的抄了,自己不喜欢问班里的同学,也不想去承认不如他们,所以深切体会到这些默默野蛮生长的天涯同路人的艰辛,最后还是愿自己这些微小的工作可以帮到你们,如有错误请多多指教,阿里嘎到~