01分数规划,最近是因为牛客网暑假训练赛第五场的A题才发现这个东西…………
其实说白了,就是一条公式的推导,然后推着推着就发现可以用二分去找答案,
就是这样,当然,也可以用Dinkelbach算法,不过我没有学,所以就不说这个了
先给你两个数列s[i],c[i];求去掉k个i后, ∑(s[i])/∑(c[i])的最大值
我们定义x[i]选或不选,即求一个选择方案使得R=∑(a[i]*x[i])/∑(b[i]*x[i])取得最值
设F(L)=∑(a[i]*x[i])-L*∑(b[i]*x[i]);(可以看到L=0时就是目标值R)
F(L)=∑((a[i]-L*b[i])*x[i]);(这时发现F(L)随着L的增大而减小,因此可以二分找答案)
到这里分析就结束了
这是poj2976Dropping tests 入门题
#include<iostream>
#include <iomanip>
#include<algorithm>
using namespace std;
#define MAX 1005
const double eps=1e-9;
double a[MAX],b[MAX];
double d[MAX];
int n,k;
bool C(double x)
{
for(int i=0;i<n;i++)
d[i]=(a[i]-x*b[i]);
/*for(int i=0;i<n;i++)
cout<<d[i]<<endl;*/
double sum=0;
sort(d,d+n);
for(int i=k;i<n;i++)
sum+=d[i];
return sum>0;
}
int main()
{
while(cin>>n>>k)
{
if(n==0&&k==0)break;
for(int i=0;i<n;i++)
cin>>a[i];
for(int j=0;j<n;j++)
cin>>b[j];
double ans=0;
double mid;
double lb=0,ub=100.0;
while(ub-lb>eps)
{
mid=(lb+ub)/2;
if(C(mid))lb=mid;
else ub=mid;
}
printf("%.0f
",ub*100);
}
return 0;
}
还有牛客网的
题目:链接:https://www.nowcoder.com/acm/contest/143/A
来源:牛客网
题目描述
Kanade selected n courses in the university. The academic credit of the i-th course is s[i] and the score of the i-th course is c[i].
At the university where she attended, the final score of her is
Now she can delete at most k courses and she want to know what the highest final score that can get.
输入描述:
The first line has two positive integers n,k
The second line has n positive integers s[i]
The third line has n positive integers c[i]
输出描述:
Output the highest final score, your answer is correct if and only if the absolute error with the standard answer is no more than 10-5
备注:
1≤ n≤ 105
0≤ k < n
1≤ s[i],c[i] ≤ 10^3
这是代码:
#include<bits/stdc++.h>
using namespace std;
#define MAX 100005
const double eps=1e-9;
double a[MAX],b[MAX],p[MAX];
int n,k;
double lb=0,ub=1000.0;
double mid;
bool C(double x)
{
memset(p,0,sizeof(p));
for(int i=0;i<n;i++)
p[i]=a[i]*b[i]-x*a[i];
sort(p,p+n);
double sum=0;
for(int i=k;i<n;i++)
{
sum+=p[i];
}
return sum>0;
}
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++)
cin>>a[i];
for(int j=0;j<n;j++)
cin>>b[j];
while(ub-lb>eps)
{
mid=(lb+ub)/2;
if(C(mid))lb=mid;
else ub=mid;
}
cout<<setprecision(11)<<mid<<endl;
return 0;
}
最后给出学习的链接:https://blog.csdn.net/Hhaile/article/details/8883652
其实还有最优比率生成树问题、最优比率环问题等,这些还要抓紧时间学!