背包问题

题目:从n个不同价值、不同重量的物品中选取一部分,在不超过限定的总重量的前提下,使该部分的价值最大。这里假定的总重量不超过n个物品的总重量总和,且没有一样物品的重量超过限定的总重量。

分析: 如果用x表示物品的重量, y表示物品价值, y/x斜率表示物品的单位价值. 那么通过斜率给所有物品排序后,  按顺序从大到小选取物品就是一种总价值比较大的的方法,  并且每一次选取的物品斜率递减. 用当前总价值/当前总重量得到一个当前总斜率, 如果希望得到一种选取方法使最后的价值大于当前总价值, 那么必须保证每一次选取物品的斜率都要大于当前总斜率(因为每次选取的物品斜率都是递减的, 如果选取的物品斜率小于等于总斜率, 那么最后的价值不可能超过总价值)

 

代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>


using namespace std;

 


class Point
{
public:
 int x;
 int y;
 double ymulx;

 Point(int xx, int yy) :x(xx), y(yy) {ymulx = (double)y/x;}

 friend bool operator> (const Point& p1,const Point& p2)
 {
  return p1.ymulx > p2.ymulx;
 }
 friend bool operator< (const Point& p1,const Point& p2)
 {
  return p1.ymulx < p2.ymulx;
 }

 friend void print(Point& p)
 {
  cout<<p.x<<" "<<p.y<<" "<<p.ymulx<<endl;
 }
};

 


int getmax_y(int limit_x, Point* it, const Point* it_end);
int getmax_y(int limit_x, int limit_y, Point* it, const Point* it_end);

 


int main()
{
 int x, y, limit_x;
 vector<Point> vp;

 cin>>limit_x;

 while(cin>>x>>y)
 {
  vp.push_back(Point(x,y));
 }

 sort(vp.begin(), vp.end(), greater<Point>());
 cout<<getmax_y(limit_x, vp.begin(), vp.end())<<endl;

 return 0;
}

 

 

int getmax_y(int limit_x, Point* it, const Point* it_end)
{
 int limit_y = 0, temp_limit_x = limit_x;
 Point* temp_it = it;

 if(limit_x == 0) return 0;
 while(temp_it < it_end)
 {
  if(temp_it->x <= temp_limit_x)
  {
  temp_limit_x = temp_limit_x - temp_it->x;
  limit_y = limit_y + temp_it->y;
  }
  temp_it++;
 }

 if(limit_y == 0) return 0;
 return getmax_y(limit_x, limit_y, it, it_end);
}


int getmax_y(int limit_x, int limit_y, Point* it, const Point* it_end)
{
 Point temp_point(limit_x, limit_y);
 int max_y = 0, temp;

 while(it < it_end)
 {
  if(*it < temp_point) break;
  if(it->x > limit_x) {it++; continue;}
  if(it->y > limit_y)
  {
   max_y = it->y + getmax_y(limit_x - it->x, it+1, it_end);
   temp_point = Point(limit_x, max_y);
   it++;
   continue;
  }
  temp = getmax_y(limit_x - it->x, limit_y - it->y, it+1, it_end) + it->y;
  if(temp > max_y) max_y = temp;
  it++;
 }

 return max_y;
}

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值