洛谷 P4377 [USACO18OPEN]Talent Show + 分数规划

分数规划

分数规划可以用来处理有关分数即比值的有关问题。

而分数规划一般不单独设题,而是用来和dp,图论,网络流等算法结合在一起。

而基础的做法一般是通过二分。

二分题目我们都知道,需要求什么的最小或最大值,就二分什么。

而该最小或最大值都会满足单调性。

设当前最大值为\(maxn\),如果存在比值使得比\(maxn\)大,则有\(y/x>maxn\),化简得:\(y-x*maxn>0\)

就可以更新答案。所以满足二分性(即\(maxn\)越大则\(y-maxn*x\))越小则越难更新答案。

而二分check可以通过排序求得\(y[i]-x[i]*maxn\)的最大值,然后直接贪心取最大值,最后判断是否大于0即可

该题目

而对于该题来说,贪心的话显然不能通过排序求最大值,因为还有一个重量限制,所以可以用背包。

重量即为原数据的重量,价值即为\(y[i]-x[i]*maxn\),在转移时需要把所有重量大于W的最后都转移到W上

最后方便统计。

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, m, dp[100100];
struct dat {		
	int w, t;      	
	int bizhi;	   	
}data[1001000];	   	
bool check(int mid)	
{				   	
	memset(dp, 128, sizeof(dp));
	dp[0] = 0;	   	
	for (int i = 1; i <= n; i++)
		data[i].bizhi = data[i].t - mid * data[i].w;
	int ha = dp[m];	
	for (int i = 1; i <= n; i++)
		for (int j = m; j >= 0; j--)
			if (dp[j] != ha)
			 	dp[min(m, j + data[i].w)] = max(dp[min(m, j + data[i].w)], dp[j] + data[i].bizhi);//取min的意义是为了让所有质量都大于m的都转移到一个地方 
	if (dp[m] >= 0) return 1;//如果存在一个价值使得能够>=0即满足条件,则该mid可以,寻找更大的 
	else return 0;	
}					
signed main()					  							
{					
 	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%lld%lld", &data[i].w, &data[i].t), data[i].t *= 1000;
	int l = 0, r = 150000, ans;
	while (l <= r)	
	{
		int mid = (l + r) / 2;
		if (check(mid))		
			l = mid + 1, ans = mid;
		else
			r = mid - 1;
	}
	printf("%lld", ans);
	return 0;
}
posted @ 2019-07-21 19:44  DAGGGGGGGGGGGG  阅读(177)  评论(0编辑  收藏  举报