POJ 3111 K Best 二分

K Best POJ 3111 二分

传送门:http://poj.org/problem?id=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=1kvijj=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) (1kn100000).

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 0vi106,1wi106, 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 InputSample 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=1kvijj=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=1kvijj=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} xj=1kwij<=j=1kvij
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=1kvijxj=1kwij 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=1kvijxj=1kwij
据此,在编写check函数时,我们可以先把所有的 v i ∗ x − w i v_i*x-w_i vixwi存在一个数组里,从大到小排序取前 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 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值