[ 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值