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