0-1背包--回溯法

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 100000
int n,c;
int cp=0,cw=0,bestp=0;//cp是当前价值,cw是当前重量,bestp是当前最优值。
int w[N],p[N],x[N],bestx[N];//bestx数组是记录最优解。
int Bound(int i)//求右子树上界;此时物品可以拆装
{
    int cleft=c-cw;
    int bp=cp;
    while(i<=n&&w[i]<=cleft)
    {
        cleft-=w[i];
        bp+=p[i];
        i++;
    }
    if(i<=n)
        bp+=p[i]*cleft/w[i];//拆装物品
    return bp;
}
void Backtrack(int i)
{
    if(i>n)
    {
        if(cp>bestp)
        {
            bestp=cp;
            for(int i=1;i<=n;i++)
            {
                bestx[i]=x[i];
//                cout<<x[i]<<" ";
            }
//            cout<<endl;
        }
        return ;
    }
    if(cw+w[i]<=c)//进去左子树
    {
        x[i]=1;
        cw+=w[i];
        cp+=p[i];
        Backtrack(i+1);
        cw-=w[i];
        cp-=p[i];
    }
    if(Bound(i+1)>bestp)//进去右子树
    {
//        printf("Bound(%d+1)=%d\n",i,Bound(i+1));
        Backtrack(i+1);
    }
}
int main()
{
    cin>>n>>c;
    for(int i=1;i<=n;i++)
    {
        cin>>w[i]>>p[i];
    }
    float a,b;
    for(int i=1;i<=n;i++)//按单位价值进行排序
    {
        for(int j=i+1;j<=n;j++)
        {
            a=(float)p[i]/w[i];
            b=(float)p[j]/w[j];
            if(a<b)
            {
                int t;

                t=w[i];
                w[i]=w[j];
                w[j]=t;

                t=p[i];
                p[i]=p[j];
                p[j]=t;
            }
        }
    }
//    for(int i=1;i<=n;i++)
//        cout<<p[i]<<" ";
//    cout<<endl;
    Backtrack(0);
    printf("%d\n",bestp);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38588998/article/details/81355468