与利润有关的背包问题(贪心算法,深度优先搜索)

 

/**< 1th exmaple: */
/** \brief
 *  一个商人带着一个能装m千克的背包去乡下收购货物,
 * \ 现有n种货源,且第i种货物有wi千克,可获利pi元,
 * \ 如何收购商品,才能使利润最大,注意此时物品可以拆零。
 * \return
 * data:
        5 10
        4 5
        2 6
        3 4
        8 15
        5 18
 */

/**< 贪婪算法解决,

收获:对于一个数组内的值,如果要从小到大或者重大到小进行选择,可以开一个choose数组进行存储下标。但这个程序用了O(n^2)的时间复杂度,等好的做法应是开一个结构来存储下标和值,然后进行排序,时间复杂度O(n*lgn),或许还有好的算法吧,这是我目前所知道的较好的一个算法。

/**< 1th exmaple: */
/** \brief
 *  一个商人带着一个能装m千克的背包去乡下收购货物,
 * \ 现有n种货源,且第i种货物有wi千克,可获利pi元,
 * \ 如何收购商品,才能使利润最大,注意此时物品可以拆零。
 * \return
 * data:
        5 10
        4 5
        2 6
        3 4
        8 15
        5 18
 */

/**< 贪婪算法解决 */
#include <iostream>

using namespace std;
struct infor
{
    double weight,value,price;
};
int main()
{
    int sum_cap,sum_size;
    cout << "输入总的物品数量及背包的容量:\n";
    cin >> sum_size >> sum_cap ;
    cout << "输入" << sum_size << "件物品的重量及价值:\n";
    infor matr[sum_size+1];
    int sum_weight=0;
    for(int i=1;i<=sum_size;++i)
    {
        cin >> matr[i].weight >> matr[i].value;
        matr[i].price=matr[i].value/matr[i].weight;
        sum_weight+=matr[i].weight;
    }
    if(sum_weight<=sum_cap)
        cout << "choose total\n";
    else
    {
        int choose[sum_size+1]; //< choose 为索引表,得到所选物品顺序的同时,又不改变物品原有顺序
        for(int i=1;i<=sum_size;++i)
        {
            int maxi=1;
            for(int j=2;j<=sum_size;++j)
                if(matr[j].price>matr[maxi].price)
                    maxi=j;
            matr[maxi].price=0; //< 得到最大价值的物体标号后,要把它置为0,防止下次重复选择
            choose[i]=maxi;
        } //想了一下,choose数组的处理是否也可以称之为数据的离散化,emm,应该是吧!
        int k;
        double sum=0,sum_value=0; //注意,sum及sum_value的数据类型取double是应该的
        for( k=1;k<=sum_size&&sum<=sum_cap;++k)
        {
            sum+=matr[choose[k]].weight;
            sum_value+=matr[choose[k]].value;
        }

        if(sum!=sum_cap)    //有可能sum比总容量还要多,则要去掉最后一件商品的一定数量
        {
            sum_value-=matr[choose[k-1]].value/matr[choose[k-1]].weight*(sum-sum_cap);
            matr[choose[k-1]].weight-=(sum-sum_cap);
        }

        for(int h=1;h<k;++h)
            cout << choose[h] << "th: " << "item choose weight is  " << matr[choose[h]].weight << endl;
        cout << "sum weights are: " << sum_cap << endl;
        cout << "sum values is: " <<  sum_value << endl;
    }
    cout << "Hello world!" << endl;
    return 0;
}

/**< 2th exmaple: */
/** \brief
 *  一个商人带着一个能装m千克的背包去乡下收购货物,
 * \ 现有n种货源,且第i种货物有wi千克,可获利pi元,
 * \ 如何收购商品,才能使利润最大,注意此时物品不可以拆零。
 * \ data : 5 8
            3 5 1 2 2
            4 5 2 1 3
 *
 * \  深度优先搜索算法解决 :
      void DFS(int index,int sumweight,int sumvalue):
      表示选择第index件物品,已经选择的物品的总重量为sumweight,
      已经选择的物品的总价值为sumvalue
*/

/**< 2th exmaple: */
/** \brief
 *  一个商人带着一个能装m千克的背包去乡下收购货物,
 * \ 现有n种货源,且第i种货物有wi千克,可获利pi元,
 * \ 如何收购商品,才能使利润最大,注意此时物品不可以拆零。
 * \ data : 5 8
            3 5 1 2 2
            4 5 2 1 3
 *
 * \  深度优先搜索算法解决 :
      void DFS(int index,int sumweight,int sumvalue):
      表示选择第index件物品,已经选择的物品的总重量为sumweight,
      已经选择的物品的总价值为sumvalue
*/


#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
void DFS(int index,int sumweight,int sumvalue);
const int maxn=101;
int n,v,w[maxn],c[maxn],maxvalue=-1;
vector<int> temp,ans;  //ans为最终的最优方案的物品下标,temp为局部最优方案的物品下标
int main()
{
    cout << "输入物品的数量,以及背包的容量:\n";
    cin >> n >> v;
    cout << "输入这些物品的重量:\n";
    for(int i=0;i<n;++i)
        cin >> w[i];
    cout << "输入这些物品的价值:\n";
    for(int i=0;i<n;++i)
        cin >> c[i];
    DFS(0,0,0);
    cout << "选择的物品标号为:\n";
    for(auto s:ans)
        cout << "第" << s+1 << "件" << endl;
    cout << "总价值为:" << maxvalue << endl;
    return 0;
}


void DFS(int index,int sumweight,int sumvalue)//把选择的物品下标也算出来了
{
    if(index==n||sumweight>v)    //递归边界
        return;
    temp.push_back(index);
    if(sumweight+w[index]<=v)
    {
        if(sumvalue+c[index]>maxvalue)
        {
            maxvalue=sumvalue+c[index];
            ans=temp;
        }
        DFS(index+1,sumweight+w[index],sumvalue+c[index]);//递归式
    }
    temp.pop_back();
    DFS(index+1,sumweight,sumvalue);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值