赞
踩
3.设置程序运行时一个构造最优解变量,该变量对应的最优值与当前最优解对于的最优值对比,如果优于当前最优解,则将覆盖当前最优解;如果与当前最优解对应的值相等,则同时保存两个最优解。
以下是具体的源代码:
- #include "stdafx.h"
- #include <iostream>
- using namespace std;
-
- typedef int Typew;
- typedef int Typep;
-
- //物品类
- class Object{
- friend class Knap;
- public:
- int operator <= (Object a) const{
- return (d >= a.d);
- }
- private:
- int ID; //物品编号
- Typew w; //物品重量
- Typep p; //物品价值
- float d; //单位重量价值
- };
-
- //0-1背包问题的主类
- class Knap{
- public:
- Knap(Typew *w, Typep *p, Typew c, int n);
- Typep Knapsack();//回溯法解决0-1背包问题的主函数
- //回溯法求解01背包问题
- void BackTrack(int floor);
- //负责打印最优值和最优解,以物品编号的顺序打印结果
- void print();
- private:
- //计算结点价值上界
- Typep Bound(int i);
- Typew c; //背包容量
- int n; //物品总数
- Object *Q; //在Q数组中存放的物品以单位重量价值降序排序
- Typew cw; //当前装包重量
- Typep cp; //当前装包价值
- int *cbestx; //当前最优解
- int count; //最优解的个数
- int *bestx[10]; //最优解,最优解的个数不超过10个。
- Typep bestp; //最优值
- Typep oldbestp; //用于回溯法边界处理,保存上一次最优值
- };
-
- Knap::Knap(Typew *w, Typep *p, Typew c, int n)
- {
- //初始化
- Typew W = 0;
- Typep P = 0;
- count = 0;
- this->c = c;
- oldbestp = 0;
- this->n = n;
- cw = 0;
- cp = 0;
- Q = new Object[n];
- for(int i =0; i<n; i++)
- {
- Q[i].ID = i+1;
- Q[i].d = 1.0*p[i]/w[i];
- Q[i].w = w[i];
- Q[i].p = p[i];
- P += p[i];
- W += w[i];
- }
- //所有物品的总重量小于等于背包容量c
- if (W <= c)
- {
- bestp = P;
- int *newbestx = new int[n];
- for(int i =0; i<n; i++)
- {
- newbestx[i] = 1;
- }
- bestx[count++] = newbestx;
-
- }
- //所有物品的总重量大于背包容量c,存在最佳装包方案
- //采用简单冒泡排序
- for(int i = 0; i<n-1; i++)
- for(int j = 0; j<n-i-1; j++)
- {
- if(Q[j].d < Q[j+1].d)
- {
- Object temp = Q[j];
- Q[j] = Q[j+1];
- Q[j+1] = temp;
- }
- }
-
- }
-
- Typep Knap::Knapsack()
- {
- if(count > 0) //背包容量足够大,在初始化时已经将所有物品装入背包
- {
- print();
- return bestp;
- }
- else //背包容量小于物品所有重量,存在最优装包方案
- {
- cbestx = new int[n];
- BackTrack(0); //从数组Q下标0,首结点开始回溯法求解
- }
-
- }
-
- void Knap::BackTrack(int floor)
- {
- if(floor > n-1) //已经到了子集树中的叶子结点
- {
- if( cp == oldbestp ) //说明可能有多个最优解
- {
- int *newbe = new int[n];
- for (int i = 0; i < n; i++)
- {
- newbe[i] = cbestx[i];
- }
- bestx[count++] = newbe;
- }
- if( cp > oldbestp) //说明最优解需要更新同时只有一个
- {
- count = 0;
- int *newbe = new int[n];
- for (int i = 0; i < n; i++)
- {
- newbe[i] = cbestx[i];
- }
- bestx[count++] = newbe;
- oldbestp = cp;
- }
- }
- else
- {
- //选取数组Q下标为floor的物品,满足背包容量约束
- if (c >= cw + Q[floor].w)
- {
- cw += Q[floor].w;
- cp += Q[floor].p;
- if(cp >= bestp)
- bestp = cp;
- cbestx[floor] = 1;
- BackTrack(floor + 1);
- cw -= Q[floor].w;
- cp -= Q[floor].p;
- }
- //舍去数组Q下标为floor的物品,满足限界函数
- if(cp + Bound(floor + 1) >= bestp)
- {
- cbestx[floor] = 0;
- BackTrack(floor + 1);
- }
-
- }
- }
-
- void Knap::print()
- {
- Typep *original = new int[n+1];
- cout<<"以下每行为一种解法:"<<endl;
- for (int i = count-1; i >= 0; i--)
- {
- for (int j = 0; j < n; j++)
- {
- original[Q[j].ID] = bestx[i][j];
- }
- for (int k = 1; k <= n; k++)
- {
- cout<< original[k] <<" ";
- }
- cout<<endl;
- }
- cout<<"最优解的个数:"<<count<<endl;
- cout<<"最优值:"<<bestp<<endl;
-
- }
-
- Typep Knap::Bound(int i)
- {
- Typew cleft = c - cw;
- Typep b = cp;
- while (i < n && Q[i].w <= cleft)
- {
- cleft -= Q[i].w;
- b += Q[i].p;
- i++;
- }
- if(i < n) b += Q[i].p/Q[i].w * cleft;
- return b;
- }
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- const int N = 4;
- Typew c = 7;
- Typew w[N] = {2,3,5,2};
- Typep p[N] = {6,4,8,4};
- cout<<"背包容量:"<<c <<" ,物品总数:"<< N<<endl;
- cout<<"物品重量数组:";
- for (int i = 0; i < N; i++)
- {
- cout<<w[i]<<" ";
- }
- cout<<endl;
- cout<<"物品价值数组:";
- for (int i = 0; i < N; i++)
- {
- cout<<p[i]<<" ";
- }
- cout<<endl;
- Knap K(w, p, c, N);
- K.Knapsack();
- K.print();
- system("pause");
- return 0;
- }

运行结果如下图:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。