题目:从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;
}