列表

详情


NC54302. 红的愿望

描述

......荒野的风,尘土里的残骸,群星下的嚎叫......红闻到了。那是狼的气味。红,加入狩猎。

众所周知, 红对其他鲁珀族的尾巴有一种特殊的执念。

她们都躲着红。红其实只是想......摸摸她们的尾巴。普罗旺斯的,德克萨斯的......红在她们身上,能闻到红喜欢的味道。

这天红又想去摸普罗旺斯的尾巴,但是普罗旺斯却躲得远远的,于是可怜的红只好自己一个人躲在房间里YY,他突然想到一个问题:

如果将所有鲁珀族的狗子视作有权值的节点,并在狗子间两两连带有权值的边以此构成一棵树 那么现在红要在这棵树上选出任意条边,且红希望边的总权值不小于给定的一个值 W ,同时,红不希望存在一只狗子同时出现在两条选出的边上,现在我们假设选出的边总权值为 tot_E ,选出的边上的两个狗子总权值为 tot_C ,那么在所有的选边方案中, tot_C/tot_E 的最大值是多少呢? 

现在红唯一的朋友就是刀客塔你了,请你帮红解决一下这个问题吧。

输入描述

第一行两个整数 n 和 W ,表示鲁珀族干员个数和总边权和的最小值

第二行 n 个数,表示干员的权值 a_i

接下来 n-1 行,每行三个正整数 u_i,v_i,w_i 表示两名狗子 u_i,v_i 间存在权值为 w_i 的边

输出描述

一个实数表示答案,含义如题,按四舍五入标准保留两位小数

示例1

输入:

5 7
1 3 2 5 4
1 3 3
2 3 6
4 5 4
3 5 5

输出:

1.71

说明:

现在树上有 5 只狗子,我们可以选出 (1,3) 和 (4,5) 这两条边,那么答案就是 (1+2+5+4)/(3+4)=1.714... 保留两位小数即 1.71

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 723ms, 内存消耗: 1480K, 提交时间: 2019-11-22 23:55:48

#include <bits/stdc++.h>
using namespace std;

#define ff	first
#define ss	second

typedef pair<int, int> pii;

template<typename T> T& maxx(T& x, const T& y) { return x = max(x, y); }

constexpr const int maxn = 512;
constexpr const int maxw = 128;
int a[maxn], W;
double dp[maxn][maxw][2], tmp[maxw][2], P;
vector<pair<int, pii>> adj[maxn];

bool dfs(int u, int p) {
	dp[u][0][0] = dp[u][0][1] = 0;
	for (int w = 1; w <= W; ++w) dp[u][w][0] = dp[u][w][1] = -1e10;
	for (const auto& e : adj[u]) {
		int v = e.ff;
		if (v == p) continue;
		if (dfs(v, u)) return true;
		for (int w = 0; w <= W; ++w) tmp[w][0] = tmp[w][1] = -1e10;
		for (int w = 0; w <= W; ++w) for (int _w = 0; _w <= W; ++_w) {
			maxx(tmp[min(W, w + _w)][0], dp[u][w][0] + dp[v][_w][1]);
			maxx(tmp[min(W, w + _w)][1], dp[u][w][1] + dp[v][_w][1]);
			maxx(tmp[min(W, w + _w + e.ss.ss)][1], dp[u][w][0] + dp[v][_w][0] + e.ss.ff - e.ss.ss * P);
		}
		for (int w = 0; w <= W; ++w) {
			dp[u][w][0] = tmp[w][0];
			dp[u][w][1] = max(tmp[w][0], tmp[w][1]);
		}
		if (dp[u][W][1] >= 0) return true;
	}
	return false;
}

int main() {
	int n;
	cin >> n >> W;
	for (int u = 1; u <= n; ++u) cin >> a[u];
	for (int i = 1; i != n; ++i) {
		int u, v, w;
		cin >> u >> v >> w;
		adj[u].emplace_back(v, pii(a[u] + a[v], w));
		adj[v].emplace_back(u, pii(a[u] + a[v], w));
	}
	double l = 0, r = 2e6;
	while (r - l > 1e-3) {
		P = (l + r) / 2;
		(dfs(1, 0) ? l : r) = P;
	}
	cout << fixed << setprecision(2) << (l + r) / 2 << endl;
}

C++11(clang++ 3.9) 解法, 执行用时: 1388ms, 内存消耗: 1248K, 提交时间: 2019-11-22 21:33:09

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
int n,m,a[505];
vector<pair<int,int> >E[505];
double f[2][505][105],g[2][105];
void cmax(double &x,double y){
	x=max(x,y);
}
void dfs(int u,int fa,double mid){
	for(int i=1;i<=m;++i)f[0][u][i]=f[1][u][i]=-1e20;
	f[0][u][0]=f[1][u][0]=0;
	for(auto x:E[u]){
		int v=x.first,w=x.second;
		if(v!=fa){
			dfs(v,u,mid);
			double t=a[u]+a[v]-mid*w;
			for(int i=0;i<=m;++i)g[0][i]=g[1][i]=-1e20;
			for(int i=m;~i;--i)
				for(int j=m;~j;--j){
					cmax(g[1][min(i+j,m)],f[1][u][i]+f[1][v][j]);
					cmax(g[1][min(i+j+w,m)],f[0][u][i]+f[0][v][j]+t);
					cmax(g[0][min(i+j,m)],f[0][u][i]+f[1][v][j]);
				}
			for(int i=0;i<=m;++i)
				f[0][u][i]=g[0][i],f[1][u][i]=g[1][i];
		}
	}
	for(int i=0;i<=m;++i)cmax(f[1][u][i],f[0][u][i]);
	/*
	printf("u=%d\n",u);
	for(int i=0;i<=m;++i){
		if(f[0][u][i]>-1e20)
			printf("f[0][u][%d]=%.2lf\n",i,f[0][u][i]);
		if(f[1][u][i]>-1e20)
			printf("f[1][u][%d]=%.2lf\n",i,f[1][u][i]);
	}
	*/
}
int main(){
//	freopen("test.in","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)scanf("%d",&a[i]);
	for(int i=1,x,y,z;i<n;++i){
		scanf("%d%d%d",&x,&y,&z);
		E[x].push_back({y,z});
		E[y].push_back({x,z});
	}
	double l=0,r=2e6;
	while(l+1e-3<r){
		double mid=(l+r)/2;
//		mid=2.44;
		dfs(1,0,mid);
		if(f[1][1][m]>0)l=mid;
		else r=mid;
//		return 0;
	}
	printf("%.2lf\n",l);
	return 0;
}

上一题