K Best POJ 3111 二分
Description
Demy has
n
n
n jewels. Each of her jewels has some value
v
i
v_i
vi and weight
w
i
w_i
wi.
Since her husband John got broke after recent financial crises, Demy has decided to sell some jewels. She has decided that she would keep
k
k
k best jewels for herself. She decided to keep such jewels that their specific value is as large as possible. That is, denote the specific value of some set of jewels
S
=
i
1
,
i
2
,
…
,
i
k
S = {i_1, i_2, …, i_k}
S=i1,i2,…,ik as
S
(
s
)
=
∑
j
=
1
k
v
i
j
‾
∑
j
=
1
k
w
i
j
S(s) = \begin{array}{c} \underline{\sum_{j=1}^kv_ij} \\{\sum_{j=1}^kw_ij}\end{array}
S(s)=∑j=1kvij∑j=1kwij
Demy would like to select such
k
k
k jewels that their specific value is maximal possible. Help her to do so.
Input
The first line of the input file contains
n
n
n — the number of jewels Demy got, and
k
k
k — the number of jewels she would like to keep
(
1
≤
k
≤
n
≤
100000
)
(1 ≤ k ≤ n ≤ 100 000)
(1≤k≤n≤100000).
The following n lines contain two integer numbers each — v i v_i vi and w i w_i wi ( 0 ≤ v i ≤ 106 , 1 ≤ w i ≤ 106 0 ≤ vi ≤ 106, 1 ≤ wi ≤ 106 0≤vi≤106,1≤wi≤106, both the sum of all v i v_i vi and the sum of all w i w_i wi do not exceed 107).
Output
Output k numbers — the numbers of jewels Demy must keep. If there are several solutions, output any one.
Sample Input | Sample Output |
---|---|
3 2 1 1 1 2 1 3 | 1 2 |
题意:
有
n
n
n 组
v
v
v 和
w
w
w ,每个
v
v
v 和
w
w
w 一一对应,对应的
v
v
v 和
w
w
w 会有同样的编号,用
i
i
i 表示。现在可以从
n
n
n 组
i
i
i 中选择
k
k
k 组,使得
S
(
s
)
=
∑
j
=
1
k
v
i
j
‾
∑
j
=
1
k
w
i
j
S(s) = \begin{array}{c} \underline{\sum_{j=1}^kv_ij} \\{\sum_{j=1}^kw_ij}\end{array}
S(s)=∑j=1kvij∑j=1kwij 最大。
考虑二分S,要使得S最大,即合法的答案x需要满足
x
<
=
∑
j
=
1
k
v
i
j
‾
∑
j
=
1
k
w
i
j
x <= \begin{array}{c} \underline{\sum_{j=1}^kv_ij} \\{\sum_{j=1}^kw_ij}\end{array}
x<=∑j=1kvij∑j=1kwij
即
x
∗
(
∑
j
=
1
k
w
i
j
)
<
=
∑
j
=
1
k
v
i
j
{x*(\sum_{j=1}^kw_ij )} <={\sum_{j=1}^kv_ij}
x∗(j=1∑kwij)<=j=1∑kvij
即
0
<
=
(
∑
j
=
1
k
v
i
j
)
∗
x
−
(
∑
j
=
1
k
w
i
j
)
0<={(\sum_{j=1}^kv_ij)*x} - {(\sum_{j=1}^kw_ij )}
0<=(j=1∑kvij)∗x−(j=1∑kwij)即
0
<
=
(
∑
j
=
1
k
v
i
j
∗
x
)
−
(
∑
j
=
1
k
w
i
j
)
0<={(\sum_{j=1}^kv_ij*x)} - {(\sum_{j=1}^kw_ij )}
0<=(j=1∑kvij∗x)−(j=1∑kwij)
据此,在编写check函数时,我们可以先把所有的
v
i
∗
x
−
w
i
v_i*x-w_i
vi∗x−wi存在一个数组里,从大到小排序取前
k
k
k项,若前
k
k
k项和
s
u
m
sum
sum满足
s
u
m
>
=
0
sum>=0
sum>=0,则答案合法,返回
1
1
1,否则返回
0
0
0。
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std ;
const ll N = 2e5+9 ;
struct node{
ll v , w , th ;
double val ;
}a[ N ];
bool cmp( node a , node b ){
return a.val > b.val ;
}
ll n , k ;
bool check( double x ){
for( int i = 1 ; i <= n ; i ++ ) { a[ i ].val = a[ i ].v - a[ i ].w*x ; }
sort( a+1 , a+1+n , cmp ) ;
double sum = 0 ;
for( int i = 1 ; i <= k ; i ++ ) sum += a[ i ].val ; //取前k个最大的
if( sum >= 0 ) return 1 ;
else return 0 ;
}
int main(){
while( scanf("%lld%lld",&n,&k) != EOF ){
for( int i = 1 ; i <= n ; i ++) { scanf("%lld%lld",&a[i].v,&a[i].w) ; a[ i ].th = i ; }
double l = 0 , r = 1e7, mid ;
for( int i = 1 ; i <= 100 ; i ++ ){
mid = (l+r)/2.0 ;
if( check( mid ) ){ l = mid ; }
else r = mid ;
}
for( int i = 1 ; i <= k ; i ++ )
printf("%lld ",a[i].th) ;
printf("\n");
}
return 0 ;
}