poj 3111 最大化平均值

链接:http://poj.org/problem?id=3111
题意:给一堆物品,给出价值和重量,要求从中选出k个物品使得单位重量的价值最大。
思路:一开始想是不是贪心,按单位价值从大到小排序,后来发现不是。还是要采用二分法枚举单位价值,从而进行判断当前的假定值是否能用所给的这些物品满足。假定当前单位价值是x,也就是判断 vi / wi >=x 是否成立,如果是那么可以x变大再进行判断,否则将x变小,从而缩小区间范围。
vi / wi >=x —> vi - wi *x >= 0 —> (vixwi) >= 0 从而构造出方程,判断这个方程是否满足,要让其尽可能的满足,要按 vixwi 进行从大到小的排序,从大的往下选。

一开始重新建了一个结构体数组来存要判断的东西和序号,后来发现并没有必要。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 100002
typedef long long ll;
struct
{
    int v;
    int w;
}a[M];
typedef struct
{
    double value;
    int num;
}state;
state s[M];
int n,m;
double mid;
bool cmp(state x,state y)
{
    return x.value > y.value;
}
bool judge(double x) //参数类型要写为double 一开始写成int  找半天。
{
    for(int i = 0;i < n;i++)
    {
        s[i].value = a[i].v - x*a[i].w;
        s[i].num = i;
    }
    sort(s,s+n,cmp);
    double sum = 0;
    for(int i = 0;i < m;i++)
    {
        sum += s[i].value;
    }
    if(sum > 1e-9) return true;
    return false;
}
void slove()
{
    double low = 0,high = 10000000;
    while(high - low > 1e-9)
    {
        mid = (high+low)/2;
        if(judge(mid))
            low = mid;
        else high = mid;
    }
    //printf("%f\n",low);
    printf("%d",s[0].num+1);
    for(int i = 1;i < m;i++)
    {
        printf(" %d",s[i].num+1);
    }
    printf("\n");
}
int main()
{
    while(scanf("%d %d",&n,&m)==2)
    {
        for(int i = 0;i < n;i++)
        {
            scanf("%d %d",&a[i].v,&a[i].w);
        }
        slove();
    }
    return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 100002
typedef long long ll;
typedef struct
{
    int v;
    int w;
    int num;
}edge;
edge a[M];
typedef struct
{
    double value;
    int num;
}state;
state s[M];
int n,m;
double mid;
bool cmp(edge x,edge y)
{
    return x.v-mid*x.w > y.v-mid*y.w;
}
bool judge(double x)  //参数类型要写为double 一开始写成int  找半天。
{
    /*for(int i = 0;i < n;i++)
    {
        s[i].value = a[i].v - x*a[i].w;
        s[i].num = i;
    }*/
    sort(a,a+n,cmp);
    double sum = 0;
    for(int i = 0;i < m;i++)
    {
        sum += a[i].v - x*a[i].w;
    }
    if(sum > 1e-9) return true;
    return false;
}
void slove()
{
    double low = 0,high = 10000000;
    while(high - low > 1e-9)
    {
        mid = (high+low)/2;
        if(judge(mid))
            low = mid;
        else high = mid;
    }
    //printf("%f\n",low);
    printf("%d",a[0].num+1);
    for(int i = 1;i < m;i++)
    {
        printf(" %d",a[i].num+1);
    }
    printf("\n");
}
int main()
{
    while(scanf("%d %d",&n,&m)==2)
    {
        for(int i = 0;i < n;i++)
        {
            scanf("%d %d",&a[i].v,&a[i].w);
            a[i].num = i;
        }
        slove();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值