小咪买东西(二分+01分数规划)

小咪买东西

小咪是一个土豪手办狂魔,这次他去了一家店,发现了好多好多(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

分析:这道题要求单位价值(题目中的总价值/总花费)最大,假设单位价值为x,那么可以知道,x = Σv / Σc。
将公式变形得到 Σv - Σc * x = 0 我们要求的是x的最大值,只要我们保证在式子Σv - Σc * x > 0的前提下,使x尽量大就可以。
x可以枚举,但是限于题目数据,需要使用二分进行查找枚举。x的初始范围只需要设定在题目所给范围内(1~1e4)即可。
可以用数组w来存储每个v和c通过公式v-c*x得到的值,然后对w[]再进行从大到小的排序,前k个就是所需要的。
前k个的和sum如果大于等于0,说明x还可以再大,如果小于零,需要让变小些。这就是二分的选择条件。

代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e4+10;
const int inf=0x3f3f3f3f;
int n,k;
int c[maxn],v[maxn];
double w[maxn];
bool judge(double x)
{
    for(int i=1;i<=n;i++)
    {
        w[i]=v[i]-x*c[i];
    }
    sort(w+1,w+1+n,greater<double>());
    double sum=0;
    for(int i=1;i<=k;i++)
    {
        sum+=w[i];
    }
    return sum>=0;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&c[i],&v[i]);
        }
        int l=1,r=maxn;
        while(l<=r)
        {
            double mid=(l+r)/2;
            if(judge(mid))
            l=mid+1;
            else
            r=mid-1;
        }
        printf("%d\n",(int)r);
    }
    return 0;
}

 

公式的变形并对其进行分析是二分中一个重要的点,找到关键未知数,进行二分查找,判断是否符合条件。
题目 解方程 也是通过对公式的观察分析得出
可以仅通过枚举a,b的值,用公式ax2+bx+c=0变形-c=a*x*x+b*x 来二分查找-c是否在所给数中判断是否符合题意。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1010;
int a[maxn];
int n,x;
bool findc(int num)
{
    int l=1,r=n;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(a[mid]<num)
        l=mid+1;
        else if(a[mid]>num)
        r=mid-1;
        else
        return true;
    }
    return false;
}
int main()
{
    cin>>n>>x;
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    bool flag=false;
    for(int i=1;i<=n;i++)
    {
    for(int j=1;j<=n;j++)
        {
            int c=a[i]*x*x+a[i]*x;
            if(findc(-c))
            {
                flag=true;
                break;
            }
        }
    }
    if(flag)
    printf("YES");
    else
    printf("NO");
    return 0;
}

 

 


posted on 2021-02-16 11:32  轻描淡写ぃ  阅读(93)  评论(0编辑  收藏  举报

导航