[ NAIPC2016 ] D Programming Team [01分數規劃 + 樹上依賴揹包]
UpCoder is looking to assign their best employees to a team tasked with designing their new and improved website, and they’re looking to you to help them form the team. There are nn potential candidates. The CEO is employee number 00, and the candidates are all assigned employee numbers ranging from 11 through nn. Each candidate is recommended by an employee with a smaller employee number. Each candidate can be described by three numbers (in addition to their employee number): their negotiated salary, their expected productivity, and the number of the employee who recommended them.
You would like to assign exactly kk candidates out of the nn total candidates to the team. The total value that you can get from these candidates is the sum of their productivities divided by the sum of their salaries. Note that you may only assign a candidate to the team if their recommender is also part of the team, or is the CEO. So, at least one candidate that you assign needs to have the CEO as a reference. The CEO handles the business aspect of the company, so s/he will not be counted as part of the kk candidates chosen for the team.
Find the maximum total value your team can provide given these constraints.
Input
Each input will consist of a single test case. Note that your program may be run multiple times on different inputs. The first line of the input will consist of two space separated integers kk and nn (1 \le k \le n \le 2,500)(1≤k≤n≤2,500), where kk is the size of the team you must form, and nn is the total number of employee candidates. Each of the following nn lines will hold three space-separated integers describing an employee. Employee 11 will be described first, then employee 22, and so on. The three integers are ss, pp and rr, where ss (1 \le s \le 10,000)(1≤s≤10,000) is the employee’s salary, p (1 \le p \le 10,000)p(1≤p≤10,000) is the employee’s productivity, and r (0 \le r < i)r(0≤r<i) is the employee number of the employee who recommended this candidate (where ii is the employee number of this candidate).
Output
Output a single real number, which represents the maximum total value you can achieve forming a team of kk employees, subject to the constraints of the problem. Output this number to exactly three decimal places, rounded (standard 5 \uparrow /4 \downarrow5↑/4↓ rounding).
樣例輸入1
1 2
1000 1 0
1 1000 1
樣例輸出1
0.001
樣例輸入2
2 3
1 100 0
1 200 0
1 300 0
樣例輸出2
250.000
題目來源
The North American Invitational Programming Contest 2016
程式碼
/***********************************************
Author :lzs
Created Time :2018年10月02日 星期二 12時05分07秒
File Name :D.cpp
************************************************/
#include <bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <string>
#include <math.h>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define rep(i, l, r) for(int i = l; i < r; i++)
#define per(i, r, l) for(int i = r; i >= l; i--)
#define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<"\n"
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int N = (int) 3000 + 11;
const int M = (int) 1e6 + 11;
const int MOD = (int) 1e9 + 7;
const int INF = (int) 0x3f3f3f3f;
const ll INFF = (ll) 0x3f3f3f3f3f3f3f3f;
const double EPS = 1e-10;
/*-----------------------------------------------------------*/
int k, n;
int clo, out[N], sz[N], rid[N];
vector <int> ve[N];
void dfs(int u){
++clo; sz[u] = 1; rid[clo] = u;
for(auto &v : ve[u]){
dfs(v);
sz[u] += sz[v];
}
out[u] = clo;
}
double dp[N][N];
double w[N];
bool f(int k){ // 注意這裡是 恰好裝滿k個容量
for(int i = 0; i <= clo + 1; i++) for(int j = 0; j <= k;j ++) dp[i][j] = -1e60;
dp[clo + 1][0] = 0;
for(int i = clo; i > 0; i--){
int x = rid[i];
for(int j = 0; j <= k; j++){
dp[i][j] = max(dp[i][j], max(dp[out[x] + 1][j], (j >= 1) ? (dp[i + 1][j - 1] + w[x]) : -1e60));
//cout << i << " " << j << " " << dp[i][j] <<"\n";
}
}
return dp[1][k] > 0;
}
int p[N], s[N];
int main(){
while(scanf("%d%d", &k, &n) != EOF){
int r;
rep(i, 0, n + 1) ve[i].clear();
for(int i = 1; i <= n; i++) {
scanf("%d%d%d", s + i, p + i, &r);
ve[r].push_back(i);
}
clo = 0; dfs(0);
double L = 0, R = INF; int cnt = 50;
while(cnt--) {
double mid = (L + R) / 2;
for(int i = 1; i <= n; i++) w[i] = p[i] - mid * s[i];
if(f(k + 1)) L = mid;
else R = mid;
}
printf("%.3lf\n", R);
}
return 0;
}