【算法】01分数规划

昨天做训练赛的时候遇到了一道求最优比率的题,不会写,学长说是用01分数规划来做,于是就看了一下入门级别的。在这里先写一下自己的心得。
01分数规划就是利用二分来查找最优比率的问题。
首先我们看一下nyoj的一道题目:Yougth的最大化
题意是每个物品都有自己的价值和重量,让你选K个物品使得这K个物品的单位价值即(v/w)最大。我们假设单位价值为t;
那么对于单个物品就有 v / w = t v/w=t ,即 v w t = 0 v-w*t=0
我们这样就可以根据这个等式二分查找 t t 的最大值
我们用一个数组记录下来每个物品 v w t v-w*t 的值,然后进行排序再二分。二分的条件是 i = 1 n v i w i t > = 0 \sum_{i=1}^{n}{vi-wi*t}>=0

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define clr(s, x) memset(s, x, sizeof(s))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
inline int read(){int r=0;char c=getchar();while(c<'0'||c>'9') {c=getchar();}while(c>='0'&&c<='9') {r=r*10+c-'0';c=getchar();}return r;}
inline ll readll(){ll r=0;char c=getchar();while(c<'0'||c>'9') {c=getchar();}while(c>='0'&&c<='9') {r=r*10+c-'0';c=getchar();}return r;}
inline ll qpow(ll a,ll b,ll mod){ll res=1;while(b){if(b&1)res = (res*a)%mod;a=(a*a)%mod;b>>=1;}return res;}
inline ll gcd(ll a,ll b){while(b^=a^=b^=a%=b);return a;}
const double eps = 1e-10;
const ll LLINF = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int MAXN = 1e6;
const int MAXM = 1e5;
//v/w=单价->v-w*单价==0 
struct node{
	double w,v;
}a[MAXN];
double re[MAXN];
int n,k;
bool jud(double x){
	for(int i=1;i<=n;i++){
		re[i]=a[i].v-a[i].w*x;
	}
	sort(re+1,re+n+1);
	double sum=0;
	for(int i=n;i>n-k;i--){
		sum+=re[i];
	}
	return sum>=0?1:0;
}
int main(){
	while(cin>>n>>k){
		double mxx=-INF;
		for(int i=1;i<=n;i++){
			cin>>a[i].w>>a[i].v;
			mxx=max(mxx,a[i].v/a[i].w);
		}
		double l=0;
		double r=mxx;
		double mid;
		while(r-l>eps){
			mid=(l+r)/2;
			if(jud(mid)){
				l=mid;
			}
			else{
				r=mid;
			}
		}
		printf("%.2lf\n",l);
	}
	return 0;
}

另一道poj类似的题目Dropping tests
让你删除k个物品使得比率最大,其实就是拿n-k个物品。

#include<iostream>
#include<algorithm>
using namespace std;
const double eps = 1e-10;
typedef long long ll;
const int MAXN = 1e5;
const int MAXM = 1e5;
//a/b==t a-b*t==0//二分t即可
double a[MAXN];
double b[MAXN];
double re[MAXN];
int n,k;
bool cmp(double a,double b){
	return a>b;
} 
bool jud(double x){
	for(int i=1;i<=n;i++){
		re[i]=a[i]-b[i]*x;
	}
	sort(re+1,re+n+1,cmp);
	double sum=0;
	for(int i=1;i<=n-k;i++){
		sum+=re[i];
	}
	return sum>=0?1:0;
}
int main(){
	while(cin>>n>>k&&(n+k)){
		for(int i=1;i<=n;i++) cin>>a[i];
		for(int i=1;i<=n;i++) cin>>b[i];
		double mxx=0;
		for(int i=1;i<=n;i++) mxx=max(mxx,a[i]/b[i]);
		double l=0;
		double r=mxx;
		double mid;
		while(r-l>eps){
			mid=(l+r)/2;
			if(jud(mid)){
				l=mid;
			}
			else r=mid;
		}
		cout<<(ll)((l)*100.0+0.5)<<endl;
	}
	return 0;
}
 

猜你喜欢

转载自blog.csdn.net/duanghaha/article/details/82930281