来,捏捏大佬牛子:https://blog.csdn.net/peachhhh/article/details/111475680
#include<iostream>
#include<algorithm>
using namespace std;
class Things;
bool cmp(Things a,Things b);
class Things{ //物品类
public:
double w; //每个物品的重量
double v; //每个物品的价值
double ratio; //每个物品的单位重量价值
friend bool cmp(Things a,Things b){ //按照单位重量价值排序
return a.ratio > b.ratio;
}
};
class Knap{ //背包类
public:
Things *t; //物品数组
int *temp_step; //当前容纳方案
int *best_step; //最优容纳方案
int *cnt; //每层记录进入儿子种类
double bestv; //最优价值
int num; //物品数量
double c; //背包容量
public:
/* 背包初始化 */
void Initial(){
cout<<"please input the number of each things and the capacility of kanpsack: "<<endl;
cin>>num>>c;
bestv = 0;
t = new Things[num * 2];
temp_step = new int[num * 2];
best_step = new int[num * 2];
cnt = new int[num * 2];
for(int i = 0;i <= num;i++)cnt[i] = 0;
cout<<"please input the value of each thing: "<<endl;
for(int i = 0;i < num;i++)cin>>t[i].v;
cout<<"please input the weight of each thing: "<<endl;
for(int i = 0;i < num;i++){
cin>>t[i].w;
t[i].ratio = t[i].v / t[i].w;
}
sort(t,t + num,cmp);
}
/* 记录最优方案 */
void Save(){
bestv = 0;
for(int i = 0;i <= num;i++){
best_step[i] = temp_step[i];
bestv += temp_step[i] * t[i].v;
}
}
/* 约束函数 */
bool Limit(int depth){
double tempc = 0;
for(int i = 0;i < depth;i++)tempc += (temp_step[i] * t[i].w);
if(tempc + t[depth].w <= c)return true;
else return false;
}
/* 限界函数 */
bool Bound(int depth){
double tempv = 0;
double tempc = 0;
int i;
for(i = 0;i < depth;i++){
tempc += temp_step[i] * t[i].w;
tempv += temp_step[i] * t[i].v;
}
for(i = depth + 1;i < num && tempc + t[i].w <= c;i++){
tempc += t[i].w;
tempv += t[i].v;
}
if(i <= num)tempv += ((c - tempc)/t[i].w) * t[i].v;
if(tempv > bestv)return true;
else return false;
}
/* 背包非递归 */
void Knapsack_WithoutRecursion(){
int depth = 0; //当前访问的层数
while(depth >= 0){ //当层数 < 0时退出根节点即推出循环,函数结束
if(cnt[depth] <= 1){ /* cnt数组存储访问该层节点的次数:当cnt[depth]为0时即第一次访问,需进入左子树;
* 当cnt[depth]为1时即第二次访问需进入右子树
* 当cnt[depth]大于1时说明该节点的左右子树均被访问,退出该层节点depth--
* */
for(int i = cnt[depth];i <= 1;i++){ //即从 cnt[depth]从0 ~ 1依次查找左右子树
if(depth == num){ //当达到叶节点时即找到最优解,将最优解存储下来,然后按照dfs规则返回上一个节点
Save();
depth--;
}
int child = 1 - cnt[depth]; /*当cnt[depth]为0时,child为1即访问左子树
* 当cnt[depth]为1时,child为0即访问右子树*/
if(child){ //进入左子树
if(Limit(depth)){ //约束函数判断
temp_step[depth] = child;
cnt[depth]++; //访问次数自增
depth++; //向左子树探索
}
else cnt[depth]++; // 若左子树不合法,但是这也说明左子树已被访问,也许自增来达到访问右子树的条件
}
else{
if(Bound(depth)){ //限界函数判断
temp_step[depth] = child;
cnt[depth]++; //访问次数自增
depth++; //向右子树探索
}
else cnt[depth]++; // 大坑勿跳,操
}
]}
}
else{ //当cnt[depth] > 1时即cnt[depth] == 2时,说明该节点的左右子树均已被访问则按照dfs规则向上回溯,返回上一层
cnt[depth] = 0; //将cnt[depth]重新设置为0,使得下一次进入该层使为第一次进入.
depth--;
}
}
}
/* 结果显示 */
void Show(){
bestv = 0;
for(int i = 0;i < num;i++)
if(best_step[i]){
cout<<"no."<<i<<" in the knapsack."<<endl;
bestv += t[i].v;
}
cout<<"the bestv is: "<<bestv<<endl;
}
};
Knap k;
int main(){
k.Initial();
k.Knapsack_WithoutRecursion();
k.Show();
}