poj3111-K Best

poj 3111-K Best

K Best
Time Limit: 8000MS

Memory Limit: 65536K
Total Submissions: 11420

Accepted: 2948
Case Time Limit: 2000MS

Special Judge
Description
Demy has n jewels. Each of her jewels has some value vi and weight 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 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 = {i1, i2, …, ik} as
.
Demy would like to select such k jewels that their specific value is maximal possible. Help her to do so.
Input
The first line of the input file contains n — the number of jewels Demy got, and k — the number of jewels she would like to keep (1 ≤ k ≤ n ≤ 100 000).
The following n lines contain two integer numbers each — vi and wi (0 ≤ vi ≤ 106, 1 ≤ wi ≤ 106, both the sum of all vi and the sum of all 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
3 2
1 1
1 2
1 3
Sample Output
1 2
Source
Northeastern Europe 2005, Northern Subregion
法1:二分查找
∑x/∑y >= c equivalent to ∑x - ∑y * c >= 0
具有可二分性,注意用Double。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1e6 + 10;

int n, k;

struct Jewels {
    int id;
    double v, w, val;
    bool operator < (const Jewels &b) const{
        return val > b.val;
    }
}jewel[MAXN];

bool check(double flag) {
    for (int i = 1; i <= n; i++)
      jewel[i].val = jewel[i].v - flag * jewel[i].w;
    sort(jewel+1, jewel+1+n);
    double res = 0;
    for (int i = 1; i<= k; i++) 
      res += jewel[i].val;
    if (res >= 0) return true;
    return false;
}

void solve(double l, double r) {
    if (r - l < 1e-8) return;
    double mid = (l + r) / 2;
    if (check(mid))
      solve(mid, r);
    else
      solve(l, mid);
}

int main()
{
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) {
      scanf("%lf%lf", &jewel[i].v, &jewel[i].w);
      jewel[i].id = i;
    }
    solve(0, 1e7);
    for (int i = 1; i <= k; i++)
      printf("%d ", jewel[i].id);
    return 0;
} 

法2:牛頓迭代
定義:選擇靠近多項式f(x)的一個零點x0作爲迭代初值。計算x = x0 - f(x0) / f’(x0)。此時,令x0 = x,如此反覆,可得到一個方程的根。
此題我的理解是:
a)令S(v, w) = ∑v / ∑w (v, w各k個),顯然,S存在上界,該過程收斂。
b)令S0 = (v1 + …+ vk) / (w1 + … + wk)
我們的目的是要找到S1 > S0
由法1,想到 ∑v / ∑w = S0 equivalent to ∑x - ∑y * S0 = 0
sort({∑x - ∑y * S0}),找前k大的,算出的 ∑x’- ∑y’ * S0 > ∑x - ∑y * S0 = 0
所以我們找到了一個S1 > S0,該過程單調

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1e6 + 10;

int n, k;

struct Jewels {
    int id;
    double v, w, val;
    bool operator < (const Jewels &b) const{
        return val > b.val;
    }
}jewel[MAXN];

int main()
{
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) {
      scanf("%lf%lf", &jewel[i].v, &jewel[i].w);
      jewel[i].id = i;
    }
    double s0, s, bri1 = 0, bri2 = 0;
    for (int i = 1; i <= k; i++) {
      bri1 += jewel[i].v ;
      bri2 += jewel[i].w;
    }
    s0 = bri1 / bri2;
    do{
      s = bri1 = bri2 = 0;
      for (int i = 1; i <= n; i++)
        jewel[i].val = jewel[i].v - s0 * jewel[i].w;
      sort(jewel+1, jewel+1+n);
      for (int i = 1; i <= k; i++) {
        bri1 += jewel[i].v;
        bri2 += jewel[i].w;
      }
      s = bri1 / bri2;
      if(abs(s - s0) < 1e-8) break;
      s0 = s;
    }while(1);
    for (int i = 1; i <= k; i++)
      printf("%d ", jewel[i].id);
    return 0;
} 
發佈了32 篇原創文章 · 獲贊 1 · 訪問量 3986
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章