• P1642 规划 01分数规划+树形DP


    $ color{#0066ff}{ 题目描述 }$

    某地方有N个工厂,有N-1条路连接它们,且它们两两都可达。每个工厂都有一个产量值和一个污染值。现在工厂要进行规划,拆除其中的M个工厂,使得剩下的工厂依然连成一片且 总产量/总污染 的值最大。

    (color{#0066ff}{输入格式})

    第一行N M(1<N<100,1<=M<N),表示工厂个数和要拆除的个数。

    第二行N个正整数,表示每个工厂的产值[1..10000]

    第三行N个正整数,表示每个工厂的污染值[1..10000]

    接着N-1行,每行两个正整数a b(1<=a,b<=N)表示a,b之间相连。

    (color{#0066ff}{输出格式})

    总产量/总污染 的最大值,保留一位小数。

    (color{#0066ff}{输入样例})

    3 2
    2 3 4
    1 1 1
    1 2
    2 3
    

    (color{#0066ff}{输出样例})

    4.0
    

    (color{#0066ff}{数据范围与提示})

    none

    (color{#0066ff}{题解})

    显然是01分数规划问题,那么二分答案

    现在的问题是找一个大小为m的联通块

    经典树形DP,(f[i][j])为以i为根子树选j个点的最大值(i必选)

    跑树形背包即可,注意i必选的限制,所以要对所有点取max

    #include<bits/stdc++.h>
    #define LL long long
    LL read() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    template<class T> bool chkmax(T &a, const T &b) { return a < b? a = b, 1 : 0; }
    template<class T> bool chkmin(T &a, const T &b) { return b < a? a = b, 1 : 0; }
    const int inf = 0x7fffffff;
    const int maxn = 555;
    const double eps = 1e-6;
    int n, m, a[maxn], b[maxn], siz[maxn];
    double f[maxn][maxn], val[maxn], mx;
    std::vector<int> G[maxn];
    void dfs(int x, int fa) {
    	siz[x] = 1;
    	f[x][0] = 0, f[x][1] = val[x];
    	for(auto to : G[x]) {
    		if(to == fa) continue;
    		dfs(to, x);
    		siz[x] += siz[to];
    		for(int i = std::min(m, siz[x]); i >= 1; i--)
    			for(int j = 0; j < i; j++)
    				chkmax(f[x][i], f[x][i - j] + f[to][j]);
    	}
    	chkmax(mx, f[x][m]);
    }
    bool ok(double mid) {
    	for(int i = 1; i <= n; i++)
    		for(int j = 0; j <= m; j++) 
    			f[i][j] = -inf;
    	for(int i = 1; i <= n; i++) val[i] = (double)(a[i] - mid * b[i]);
    	mx = -1e18;
    	dfs(1, 0);
    	return mx >= 0;
    }
    
    int main() {
    	n = read(), m = n - read();
    	for(int i = 1; i <= n; i++) a[i] = read();
    	for(int i = 1; i <= n; i++) b[i] = read();
    	int x, y;
    	for(int i = 1; i < n; i++) {
    		x = read(), y = read();
    		G[x].push_back(y);
    		G[y].push_back(x);
    	}
    	double l = 0, r = 105050;
    	while(r - l > eps) {
    		double mid = (l + r) / 2.0;
    		if(ok(mid)) l = mid;
    		else r = mid;
    	}
    	printf("%.1f
    ", l);
    	return 0;
    }
    
  • 相关阅读:
    防抖函数
    video.js汉化
    vscode 设置
    webpack配置
    寄生组合继承
    数组排序
    操作节点的方法
    vscde软件
    vue目录详解
    前端
  • 原文地址:https://www.cnblogs.com/olinr/p/10652961.html
Copyright © 2020-2023  润新知