• 01背包问题(回溯算法实现)


        问题描述:有n件物品和一个容量为c的背包。第i件物品的价值是v[i],重量是w[i]。求解将哪些物品装入背包可使价值总和最大。所谓01背包,表示每一个物品只有一个,要么装入,要么不装入。
        今 天下午的算法复习课,老师提的各种算法经典问题时,出现频率就是01背包问题了!动态规划、回溯法、分支限界法,在贪心算法时也提到注意背包问题,当然 01背包问题不能用贪心算法实现,不能保证能得到最优解。回溯法是最近学的,所以试着用C语言将其实现了下,下面作以分析,后期将会继续用其他两种算法实 现01背包问题,并做比较。
      回溯法:01背包属于找最优解问题,用回溯法需要构造解的子集树。在搜索状态空间树时,只要左子节点是可一个可行结点,搜索就进入其左子树。对于右子树时,先计算上界函数,以判断是否将其减去,剪枝啦啦!
      上界函数bound():当前价值cw+剩余容量可容纳的最大价值<=当前最优价值bestp。
      为了更好地计算和运用上界函数剪枝,选择先将物品按照其单位重量价值从大到小排序,此后就按照顺序考虑各个物品。
       下面直接贴代码吧:

    #include <stdio.h>
    #include <conio.h>

    int n;//物品数量
    double c;//背包容量
    double v[100];//各个物品的价值
    double w[100];//各个物品的重量
    double cw = 0.0;//当前背包重量
    double cp = 0.0;//当前背包中物品价值
    double bestp = 0.0;//当前最优价值
    double perp[100];//单位物品价值排序后
    int order[100];//物品编号
    int put[100];//设置是否装入

    //按单位价值排序
    void knapsack()
    {
        inti,j;
        inttemporder = 0;
        double temp= 0.0;

       for(i=1;i<=n;i++)
           perp[i]=v[i]/w[i];
       for(i=1;i<=n-1;i++)
        {
           for(j=i+1;j<=n;j++)
               if(perp[i]<perp[j])//冒泡排序perp[],order[],sortv[],sortw[]
           {
               temp = perp[i];
               perp[i]=perp[i];
               perp[j]=temp;

               temporder=order[i];
               order[i]=order[j];
               order[j]=temporder;
               temp = v[i];
               v[i]=v[j];
               v[j]=temp;

               temp=w[i];
               w[i]=w[j];
               w[j]=temp;
           }
        }
    }

    //回溯函数
    void backtrack(int i)
    {
        doublebound(int i);
       if(i>n)
        {
           bestp = cp;
           return;
        }
       if(cw+w[i]<=c)
        {
           cw+=w[i];
           cp+=v[i];
           put[i]=1;
           backtrack(i+1);
           cw-=w[i];
           cp-=v[i];
        }
       if(bound(i+1)>bestp)//符合条件搜索右子数
           backtrack(i+1);
    }

    //计算上界函数
    double bound(int i)
    {
        doubleleftw= c-cw;
        double b =cp;
       while(i<=n&&w[i]<=leftw)
        {
           leftw-=w[i];
           b+=v[i];
           i++;
        }
       if(i<=n)
           b+=v[i]/w[i]*leftw;
        returnb;

    }


    int main()
    {
        int i;
       printf("请输入物品的数量和容量:");
        scanf("%d%lf",&n,&c);
       printf("请输入物品的重量和价值:");
       for(i=1;i<=n;i++)
        {
           printf("第%d个物品的重量:",i);
           scanf("%lf",&w[i]);
           printf("价值是:");
           scanf("%lf",&v[i]);
           order[i]=i;
        }
       knapsack();
       backtrack(1);
       printf("最有价值为:%lf\n",bestp);
       printf("需要装入的物品编号是:");
       for(i=1;i<=n;i++)
        {
           if(put[i]==1)
               printf("%d ",order[i]);
        }
        return0;
    }
    运行结果截图:



    算法复杂度分析:上界函数bound()需要O(n)时间,在最坏的情况下有O(2^n)个右子结点需要计算上界,回溯算法backtrack需要的计算时间为O(n2^n)。
       

    go to sleep......
           

  • 相关阅读:
    C#中String和string的区别
    .NET设计模式系列文章
    [python] 视频008
    [python]获取字符串类型
    【影评-转自豆瓣】疯狂原始人
    [python]文本处理1.2
    周末可以做的10件事
    [python]随机数
    [python] 字符串引用
    用户控件(.ascx)与<ul><li>以及<a>布局之小结
  • 原文地址:https://www.cnblogs.com/shuyingsoaring/p/3130640.html
Copyright © 2020-2023  润新知