非递归回溯法实现0-1背包问题

来,捏捏大佬牛子: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();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值