1. 程式人生 > >【演算法】01分數規劃

【演算法】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;
}