0/1分数规划(poj2976)

输入数列{a_{1},a_{2},.....a_{n}}和{b_{1},b_{2},....b_{n}},从两个数列中去掉k对,选择n-k对,求100*\frac{\sum_{i=1}^{n}a_{i}s_{i}}{\sum_{i=1}^{n}b_{i}s_{i}}的最大值,s_{i}取1或0分别表示选或者不选第i对数。0

我们假设 \frac{\sum_{i=1}^{n}a_{i}s_{i}}{\sum_{i=1}^{n}b_{i}s_{i}}=x

移项得f=\sum_{i=1}^{n}(a_{i}-xb_{i})s_{i}=0

y_{i}=a_{i}-xb_{i},把x,y看成变量,这就是一条条直线,题意就转换成求一个最大的x使得n-k条直线函数值为0

这n条直线的图形如下图6.4,可以看出每一条直线都是单调递减的,因此他们的和也是单调递减,因此n-k条直线的函数值也是随着x单调递减的,意味着我们总能找到一个x使得n-k条直线函数值为0。

为了节省时间,就可以用二分,二分的一个端点肯定就是0,另一个端点就是\sum_{i=1}^{n}a_{i}

0/1分数规划(poj2976)_第1张图片

#include
using namespace std;
int n,k;
struct node
{
	int a;
	int b;
	double y;
}h[1005];
bool tmp(node a,node b)
{
	return a.y>b.y;
}
bool check(double m)
{
	for(int i=0;i=0)return 1;
	else return 0;
}
int main()
{
	
	while(cin>>n>>k&&n+k!=0)
	{
		k=n-k;
		double l=0,r=0;
		for(int i=0;i>h[i].a;
			r+=h[i].a;
		}
		for(int i=0;i>h[i].b;
		for(int i=0;i<=50;i++)
		{
			double mid=(l+r)/2;
			if(check(mid))
			{
				l=mid;
			}
			else
			{
				r=mid;
			}
		}
		cout<<(int)(100*l+0.5)<

你可能感兴趣的:(数论,poj,c++,算法)