规划

题目链接:规划


这个式子显然可以01分数规划,然后问题就变成选n-m个点,并且是一个联通块的最大权值,树形dp即可。

dp[i][j] 为以 i 为根节点,选取 j 个点的最大值。然后树上做背包即可。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=110;
int n,m,sz[N]; double dp[N][N],a[N],b[N],res;
vector<int> g[N];
void dfs(int x,int fa,double mid){
	dp[x][1]=a[x]-mid*b[x]; sz[x]=1;
	for(int to:g[x]) if(to!=fa){
		dfs(to,x,mid);
		for(int j=sz[x];j>=1;j--) for(int k=sz[to];k>=1;k--)
			dp[x][j+k]=max(dp[x][j+k],dp[x][j]+dp[to][k]);
		sz[x]+=sz[to];
	}
	res=max(res,dp[x][n-m]);
}
inline int check(double mid){
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dp[i][j]=-1e9;
	res=-1e9; dfs(1,0,mid);
	return res>0;
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	for(int i=1,a,b;i<n;i++) cin>>a>>b,g[a].push_back(b),g[b].push_back(a);
	double l=0.0,r=1e6;
	for(int i=1;i<=50;i++){
		double mid=(l+r)/2;
		if(check(mid)) l=mid;
		else r=mid;
	}
	printf("%.1lf\n",l);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值