01分数规划 易懂+例题讲解 (c++)

01分数规划 :01即取还是不取,分数即所求型式为\sum \frac{a}{b},规划就是选取最好的方案。

一般情况题目给出n个物品,再给出每个物品的价值以及物重,选取k个物品,问你在所有可能选取的方案中,最大的单位价值为多少(单位价值为选取的 k 个物品的总价值和总重量的比值)。

我们选择采用二分法,进行判断。我们要求的是选取的 k 个物品的总价值和总重量的比值最大,最终求得是\sum \frac{a}{b}

所以我们在\sum \frac{a}{b}可取的区间内每次取区间中值mid,判断是否符合,符合则可以取右边区间,不符合则取左区间。

 eg:
 int l = 0, r = 1e8 + 5;
 while (l <= r)
      {
          int mid = (l + r) / 2;
          if (judge(mid)) l = mid + 1;
          else r = mid - 1;
       }

接下来是要写判断函数judge

我们知道我们所取的mid要符合 \sum \frac{a}{b}>=mid,则\sum(a-b*mid)>=0。所以我们要从大到小取

a-b*mid来相加直到k个才能保证最有可能大于等于0.

eg:
bool comp(node a,node b)//从大到小排序
{
	return a.tmp > b.tmp;
}
int  judge(double x)
{
	for (int i = 1; i <= n; i++)
    {
        a[i].tmp = a[i].v*1.0 - x * a[i].w*1.0;储存每个物品的价值-x*重量值
    }
	sort(a + 1, a + 1 + n, comp);//进行排序
	double sum = 0;
	for (int i = 1; i <= k; i++)//求和
	{
		sum += a[i].tmp;
	}
    
	return sum >= 0.0;//返回是否大于等于0
}

 

例题1: 

题目描述

wyh学长现在手里有 nnn 个物品,这 nnn 个物品的重量和价值都告诉你,然后现在让你从中选取 kkk 个,问你在所有可能选取的方案中,最大的单位价值为多少(单位价值为选取的 kkk 个物品的总价值和总重量的比值)

输入描述:

输入第一行一个整数 T(1≤T≤10)
接下来有 T 组测试数据,对于每组测试数据,第一行输入两个数 n 和 k(1≤k≤n≤100000)k
接下来有 n 行,每行两个是 a 和 b (0<a,b≤1000000)代表这个物品的重量和价值

输出描述:

对于每组测试数据,输出对应答案,结果保留两位小数

示例1

输入

1
3 2
2 2
5 3
2 1

输出

0.75

说明

对于样例来说,我们选择第一个物品和第三个物品,达到最优目的
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct node
{
	double w, v,tmp;
}a[100010];
int n, k;
bool comp(node a,node b)//从大到小排序
{
	return a.tmp > b.tmp;
}
int  judge(double x)
{
	for (int i = 1; i <= n; i++)
    {
        a[i].tmp = a[i].v*1.0 - x * a[i].w*1.0;//存储价值-x*重量
    }
	sort(a + 1, a + 1 + n, comp);//排序
	double sum = 0;
	for (int i = 1; i <= k; i++)//求和
	{
		sum += a[i].tmp;
	}
    
	return sum >= 0.0;返回是否大于等于0

}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		cin >> n >> k;
		for (int i = 1; i <= n; i++)
		{
			cin >> a[i].w >> a[i].v;
		}
		double l = 1.0, r = 1e7 + 10;
		double ans;
		for(int i=1;i<=100;i++)
		{
			double mid = (l + r) / 2;
			if (judge(mid)) l = mid+1;
			else r = mid-1;
			
		}
		printf("%.2lf\n", l-1);

	}
}

 例题2:

题目描述

小咪是一个土豪手办狂魔,这次他去了一家店,发现了好多好多(n个)手办,但他是一个很怪的人,每次只想买k个手办,而且他要让他花的每一分钱都物超所值,即:买下来的东西的总价值/总花费=max。请你来看看,他会买哪些东西吧。

输入描述:

多组数据。

第一行一个整数T,为数据组数。

接下来有T组数据。

对于每组数据,第一行两个正整数n,k,如题。

接下来n行,每行有两个正整数ci,vi。分别为手办的花费和它对于小咪的价值。

输出描述:

对于每组数据,输出一个数,即能得到的总价值/总花费的最大值。精确至整数。

示例1

输入

1
5 1
1 2
2 3
3 4
4 5
5 6

输出

2

备注:

1≤T≤10

1≤n≤104

1≤k≤n

1≤ci,vi≤104

#include<iostream>
#include<algorithm>
using namespace std;
int t;
int n, k;
struct node 
{
    int c;
    int v;
    long long sum;
}a[10005];
bool cmp(node a, node b)
{
    return a.sum > b.sum;
}
int judge(long long x)
{
    for (int i = 1; i <= n; i++)
    {
        a[i].sum = a[i].v - x * a[i].c;
    }
    sort(a + 1, a + 1 + n, cmp);
    long long num = 0;
    for (int i = 1; i <= k; i++) 
    {
        num += a[i].sum;
    }
    if (num >= 0) return 1;
    else return 0;
}
int main()
{
    cin >> t;
    while (t--)
    {
        cin >> n >> k;
        for (int i = 1; i <= n; i++) 
        
        {
            cin>>a[i].c>>a[i].v;
        }
        int l = 0;
        int r = 1e8 + 5;
        while (l <= r)
        {
            int mid = (l + r) / 2;
            if (judge(mid)) l = mid + 1;
            else r = mid - 1;
        }
        cout << l-1 << endl;
    }
    return 0;
}

很明显懂了以后,遇到这种题目就可以选择直接套用模板。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值