NYOJ914Yougth的最大化

本文介绍如何使用0-1分数规划、贪心算法及二分搜索解决物品选取问题,以实现单位重量价值最大化。文章提供了一段C++代码示例,详细展示了算法的具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述

Yougth现在有n个物品的重量和价值分别是Wi和Vi,你能帮他从中选出k个物品使得单位重量的价值最大吗?

输入
有多组测试数据
每组测试数据第一行有两个数n和k,接下来一行有n个数Wi和Vi。
(1<=k=n<=10000) (1<=Wi,Vi<=1000000)
输出
输出使得单位价值的最大值。(保留两位小数)
样例输入
3 2
2 2
5 3
2 1
样例输出

0.75


**在开始看代码之前,你需要了解三个东西,1.贪心,2.二分,3.0-1分数规划,前两个应该都知道,但是第3个东西,那可要好好的说一说

//sigma()来表示数学上的求和公式  链接 http://m.blog.youkuaiyun.com/article/details?id=8883652

这个第一个问题解释的十分详细,初中水平的数学就就能看懂的,这里就不多解释了


#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,k;
int v[10010],w[10010];
double dp[10010];//这个数组用来存我们方程子元素的结果的 
int compare(double a,double b)//sort函数的比较函数,从大到小 
{
	return a>b;
}
bool judge(double l)//判断当前是否为最优解,然后通过二分压缩区间 
{
	int i;
	double sum = 0;
	for(i=0;i<n;i++)
		dp[i] = v[i]-l*w[i];//这就是通过上面的 0-1分数规划求出来的方程,可不是你想的随随便便就写出来的 
	sort(dp,dp+n,compare);
	for(i=0;i<k;i++)//对前k项子项求和 ,当sum的值趋近于 0 的时候,传入的mid就是最优解了 
		sum+=dp[i];
	if(sum>=0)//如果sum>0 说明我们没有充分发挥价值,还要剩余,sum=0的话我们也试试能不能再大一点 
		return true;//简单来说就是mid取到一个极大值,任何比mid大的值都会使sum<0 
	else 
		return false;//这种情况下对应的就是我们所找的mid大于我们的实际最优解,实际上这个值是取不到的,也是没有意义的 
}
int main()
{
	int i;
	while(~scanf("%d%d",&n,&k))
	{
		double max = 0;
		for(i=0;i<n;++i)
		{
			scanf("%d%d",&w[i],&v[i]);
			max = v[i]*1.0/w[i] > max? v[i]*1.0/w[i] : max;//我们计算出每个物品的平均价值,最优解的范围就在 0到最大平均价值之间,这应该很容易懂的吧 
		}
		double low=0,high=max,mid;//二分搜索最优解,下界0,上界max(最大的单位价值) 
		while(high-low>0.00001)//注意对double类型的二分判断条件是小于0.00001,不懂的就去百度一下 
		{
			mid = (low+high)/2;
			if(judge(mid))//通过judge函数来压缩区间 
				low = mid;
			else 
				high = mid;
		}
		printf("%.2lf\n",mid);//保留两位输出就好 
	}
	return 0;
}




下面是纯代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,k;
int v[10010],w[10010];
double dp[10010];
int compare(double a,double b)
{
	return a>b;
}
bool judge(double l)
{
	int i;
	double sum = 0;
	for(i=0;i<n;i++)
		dp[i] = v[i]-l*w[i];
	sort(dp,dp+n,compare);
	for(i=0;i<k;i++)
		sum+=dp[i];
	if(sum>=0)
		return true;
	else 
		return false;
}
int main()
{
	int i;
	while(~scanf("%d%d",&n,&k))
	{
		double max = 0;
		for(i=0;i<n;++i)
		{
			scanf("%d%d",&w[i],&v[i]);
			max = v[i]*1.0/w[i] > max? v[i]*1.0/w[i] : max;
		}
		double low=0,high=max,mid;
		while(high-low>0.00001)
		{
			mid = (low+high)/2;
			if(judge(mid))
				low = mid;
			else 
				high = mid;
		}
		printf("%.2lf\n",mid);
	}
	return 0;
}


奈何我冒泡的算法如果打动你超时的心!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值