题目链接: http://acm.pku.edu.cn/JudgeOnline/problem?id=2976
0-1分数规划
最优比例生成树
迭代法
证明:(前几次都是看别人的,这次自己证明)
对于集合s,令l* = max{ a(x) / b(x) } = a(x*) / b(x*).l为所求的最优解,x为对应的集合
注:b(x)必须恒大于0
然后令z(l) = min{ l × b(x) - a(x) }
证明单调性:
首先若l1 > l2
z(l1) = min { l1 × b(x) - a(x) } = l1 × b(x1) - a(x1) > l2 × b(x1) - a(x1) ≥ min{ l2 × b(x) - a(x) } = z(l2)
=> z(l)是关于l的单调递增函数
再证l = l*时,z(l) = 0
若有x'使得l* × b(x') - a(x') ≤ 0
=> a(x') / b(x') ≤ l* => l* × b(x') - a(x') ≥ 0
=> l* × b(x') - a(x') = 0 即 x' = x*
再证z(l) = 0时l = l*
若z(l') = 0, l' ≤ max{a(x) / b(x)} = a(x*) / b(x*) => b(x*) × l' - a(x*) ≤ 0
=> l' = l*
最终结果是
z(l) < 0 when l < l*
z(l) = 0 when l = l*
z(l) > 0 when l > l*
从这里我们已经可以用二分l的值的方法计算答案了
但是我们要更快,证明迭代法正确性
z(l) = min{l × b(x) - a(x)}
若l1 ≠ l*
z(l1) = min { l1 × b(x) - a(x) } = l1 × b(x1) - a(x1)
令l2 = a(x1) / b(x1) => b(x1) × l2 - a(x1) = 0
若z(l1) < 0 ,则 l2 > l1,同时l* > l1
又min{ l* × b(x) - a(x) } = 0 < l* × b(x1) - a(x1) => l* > l2
由此可得 l1 < l2 < l*
z(l1) < 0时同理可得
最终结论
l1 < l2 < l*
由此,每次我们计算出l2,必然比l1接近l*,当靠近到可以忽略精度的位置时,就可以停止了
开始敲代码:
/**
* URL: http://acm.pku.edu.cn/JudgeOnline/problem?id=2976
* Author: OWenT
* Blog: http://www.owent.net
* 0-1分数规划 + 最优比例生成树 + 迭代法
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef struct
{
long a,b;
}node;
node score[1005];
double res = 0, tmp = 100;
double iter(const long &k, const long &n);
bool cmp(node a, node b)
{
return res * a.b - a.a < res * b.b - b.a;
}
int main()
{
long n, k, i;
while(cin>> n>> k, n != 0 || k != 0)
{
memset(score, 0, sizeof(score));
for(i = 0; i < n; i ++)
cin>> score[i].a;
for(i = 0; i < n; i ++)
cin>> score[i].b;
k = n - k;//去除k个就是取n-k个使得l* = max { a(x) / b(x) }
res = 0;
tmp = 100;
while(fabs(res - tmp) > 1e-6)
{
tmp = res;
res = iter(k, n);
}
printf("%.0lf\n", res * 100);
}
return 0;
}
double iter(const long &k, const long &n)
{
long i;
double tmpRA = 0, tmpRB = 0;
sort(score, score + n, cmp);
for(i = 0; i < k; i ++)
tmpRA += score[i].a, tmpRB += score[i].b;
return tmpRA / tmpRB;
}