【NOIP2013中秋节模拟】表白(love)(0/1分数规划)

  • 题意:

    • 给定\(n\)个四元组,每个四元组用\((a_i,b_i,c_i,d_i)\)表示,且如果选了\(a_i\),则\(Q+=a_i,C+=b_i\),如果选了\(C_i\),则\(Q+=C_i,C+=d_i\).
    • \(a_i\)至多选\(n_1\)个,\(c_i\)至多选\(n_2\)个,使\(Q/C\)尽量大.
    • \(n_1+n_2\le n\le 500, Q_1,Q_2\le 2000, C_1,C_2\le 50\)
  • 考虑二分答案\(t\).

  • 则题目转化为求一个选择方案,使得\[\frac{\sum_{i\in S} a_i+\sum_{j\in T} c_j}{\sum_{i\in S} b_i+ \sum_{j\in T} d_j} \ge t\].

  • 转化一下后其实是使\[\sum_{i\in S}a_i-b_i*t+\sum_{j\in T}c_j-d_j*t\],于是每个\(a_i\)变为\(a_i-b_i*t\),每个\(c_i\)变为\(c_i-d_i*t\).

  • 于是按\(a_i-c_i\)排个序,随便DP一下就好.

  • 这是典型的0/1规划题目。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

#define ldb long double
#define L register int
#define F(i, a, b) for (L i = a; i <= b; i ++)
#define G(i, a, b) for (L i = a; i >= b; i --)
#define mx(a, b) ((a) = (a) > (b) ? (a) : (b))
#define Get getchar()
#define N 510

const ldb s = 1e-9;

using namespace std;

int n, n1, n2, Q1[N], C1[N], Q2[N], C2[N];
ldb a[N], b[N], f[N][N][2], g[N][N][2], ans, l, r, m, answer;
struct node{ ldb a, b, c; } d[N];

void R(L &x) {
    char c = Get; x = 0; L t = 1;
    for (; !isdigit(c); c = Get) t = (c  == '-' ? - 1 : t);
    for (; isdigit(c); x = (x << 3) + (x << 1) + c - '0', c = Get) ; x *= t;
}

bool cmp(node x, node y) { return x.c > y.c;
}

bool Good(ldb x) {
    F(i, 1, n)
        d[i].a = (ldb) Q1[i] - x * C1[i], d[i].b = (ldb) Q2[i] - x * C2[i], d[i].c = d[i].a - d[i].b;
    sort(d + 1, d + n + 1, cmp), ans = -1e9;
    F(i, 0, n + 1) F(j, 0, n + 1) f[i][j][0] = f[i][j][1] = g[i][j][0] = g[i][j][1] = -1e9;

    f[0][0][0] = f[0][0][1] = g[n + 1][0][0] = g[n + 1][0][1] = 0;
    F(i, 1, n)
        F(j, 0, min(n1, i)) {
            if (j) f[i][j][1] = max(f[i - 1][j - 1][1], f[i - 1][j - 1][0]) + d[i].a;
            mx(f[i][j][0], f[i - 1][j][1]), mx(f[i][j][0], f[i - 1][j][0]);
        }
    G(i, n, 1)
        F(j, 0, min(n2, n - i + 1)) {
            if (j) g[i][j][1] = max(g[i + 1][j - 1][1], g[i + 1][j - 1][0]) + d[i].b;
            mx(g[i][j][0], g[i + 1][j][1]), mx(g[i][j][0], g[i + 1][j][0]);
        }

    F(i, 1, n) {
        mx(ans, f[i][n1][1] + g[i][n2][0]);
        mx(ans, f[i][n1][0] + g[i][n2][1]);
    }
    
    return ans >= 0;
}

int main() {
    freopen("love.in", "r", stdin) ;
    freopen("love.out", "w", stdout) ;
    
    R(n), R(n1), R(n2);
    F(i, 1, n) R(Q1[i]), R(C1[i]), R(Q2[i]), R(C2[i]);

    l = 0, r = 1000000;
    while (l <= r) {
        m = (l + r) / 2;
        if (Good(m)) answer = m, l = m + s; else r = m - s;
    }
    
    printf("%Lf", answer);
}

猜你喜欢

转载自www.cnblogs.com/Pro-king/p/9383534.html
今日推荐