回溯法解决0-1背包问题(迭代)

#include<bits/stdc++.h>
using namespace std;
class Knap{
    friend int Knapsack(int*,int*,int,int,Knap&);
public:
    int c;      //背包容量
    int n;      //物品个数
    int* w;     //重量信息
    int* p;     //价值信息
    int cw;     //当前重量
    int cp;     //当前价值
    int bestp;  //当前最优价值
    int *x,     //当前解
        *bestx; //当前最优解
    int Bound(int i);            //限界函数
    void Iterative_Backtrack();  //迭代深度优先遍历
};
int Knap::Bound(int i){          //求解第i层的限界函数(按照背包问题的贪心策略)
    int cleft = c - cw;
    int b = cp;
    while(i<=n&&w[i]<=cleft){
        b += p[i];
        cleft -= w[i];
        i++;
    }
    if(i<=n) b += cleft*(p[i]/w[i]);
    return b;
}
void Knap::Iterative_Backtrack(){
    int t = 1;
    while(t>0){                      //t<=0时表示已经遍历完成,结束循环 
        while(t<=n && cw+w[t]<=c){   //如果能装下去就继续装,即深度访问其左儿子
            x[t] = 1;
            cw += w[t];
            cp += p[t];
            t++;
        }
        if(t > n){                  //如果到达叶子节点,更新最优值和最优解,并输出当前最优解
            for(int i=1;i<=n;i++){
                bestx[i] = x[i];
               }
            bestp = cp;
            for(int i=1;i<=n;i++){
                cout<<x[i]<<" ";
            }
            cout<<" value "<<cp<<endl;
}
        else{                     //如果没有到达叶子节点,则访问其右儿子
            x[t] = 0;
            t++;
        }
        while(Bound(t+1) <= bestp){  //如果右儿子不满足限界条件则需回溯
           t--;
           while(t>=1 && !x[t]){     //回溯到右儿子没有被访问过的节点
                t--;
            }
            if(t<=0)
                break;
           x[t] = 0;                //访问最终回溯节点的右儿子
           cw -= w[t];              //更新相应值
           cp -= p[t];
                                    //再次进入循环判断右儿子是否符合限界函数
          }
}
}
class Object{                                        //物品类
    friend int Knapsack(int*,int*,int,int,Knap&);
    friend bool cmp(Object,Object);
private:
    int id;
    double aver;
};
bool cmp(Object a,Object b){
    return a.aver>b.aver;
}
int Knapsack(int* w,int* p,int c,int n,Knap& K){   //初始化以及调用重要的函数,因为要访问类内私有成员所以声明为友元函数
    int W = 0;
    int P = 0;
    Object* Q = new Object[n];
    for(int i=1;i<=n;i++){
        Q[i-1].id = i;
        Q[i-1].aver = 1.0*p[i]/w[i];
        P += p[i];
        W += w[i];
}
    if(W<c) return P;                 
    sort(Q,Q+n,cmp);                      //依照单位重量的价值进行排序
    K.p = new int[n+1];
    K.w = new int[n+1];
    K.x = new int[n+1];
    K.bestx = new int[n+1];
    for(int i=1;i<=n;i++){                //依照物品的单位重量的价值进行初始化
        K.p[i] = p[Q[i-1].id];
        K.w[i] = w[Q[i-1].id];

    }
    K.cp = 0; K.cw = 0; K.c = c; K.n = n; K.bestp = 0;
    K.Iterative_Backtrack();             //调用重要遍历函数
    delete [] Q; delete [] K.w; delete [] K.p;delete [] K.x;
             return K.bestp;

}
void Init(int* &w,int* &p,int& c,int& n){        //输入背包的相关信息
    cout<<"input number of object and capacity of bag"<<endl;
    cin>>n>>c;
    w = new int[n+1];
    p = new int[n+1];
    cout<<"input weight of objects"<<endl;
    for(int i=1;i<=n;i++){
        cin>>w[i];
    }
    cout<<"input value of objects"<<endl;
    for(int i=1;i<=n;i++){
        cin>>p[i];
    }
}
void Print(int bestp,int n,int*& x){
    cout<<"max value is"<<endl;
    cout<<bestp<<endl;
    cout<<"The optimal solution is"<<endl;
    for(int i=1;i<=n;i++){
       cout<<x[i]<<" ";
    }
}
int main(){
    int *w=NULL,*p=NULL;
    int c,n;
    Knap K;
    Init(w,p,c,n);
    Print(Knapsack(w,p,c,n,K),n,K.bestx);
    return 0;
}
//7 150
//35 30 60 50 40 10 25
//10 40 30 50 35 40 30
//170
//开始错误写法

//void Knap::Iterative_Backtrack(){
//   int t = 1;
//   while(t > 0){
//    while(t <= n && cw+w[t] <= c){
//      cw += w[t];
//      cp += p[t];
//      t++;
//   }
//   if(t>=n){bestp = cp;}
//   else{
//    cw -= w[t];
//    cp -= p[t];
//    t--;
//   }
//   if(cp+Bound(t+1)>bestp){t++;}
//   else {t--;}
//   }
//
//void Knap::Iterative_Backtrack(){
//   int t = 1;                      //从第一层开始
//   while(t > 0){                   //当回溯到t = 0时说明已经遍历完成结束循环
//    while(t <= n && cw+w[t] <= c){ //如果可以继续装载即可以继续访问左子树,就按深度优先继续访问
//      cw += w[t];
//      cp += p[t];
//      t++;
//   }
//   if(cp+Bound(t+1) > bestp){t++;}   //当装不下t件物品时则停止访问,判断是否可以访问其右子树
//   else {                          //如果右子树也不可访问则需要回溯到上一层
//    cw -= w[t];
//    cp -= p[t];
//    t--;
//   }
//   if(t > n){bestp = cp;}          //如果来到第n+1层则得到一个解,根据约束函数和限界函数可知,此解即为目前最优解,更新
//   }
//}

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值