• loj6395. 「THUPC2018」城市地铁规划 / City


    题意

    给定一个函数(c(x))表示度数为(x)的节点权值。求构建一棵树,使得权值和最大。
    (n leq 3000)

    题解

    考虑要构建一棵树,prufer序列会是一个不错的选择。
    根据prufer的性质,每个点出现的次数为度数减1,并且总序列长度为(n - 2)
    这样就可以做一个完全背包,体积为(x - 1),价值为(c(x)),(其中((1 leq x leq n - 1)))的物品每种有无限个。
    最后求出背包大小为(n - 2)的最大价值和。
    但是注意到体积为0也有价值,却不能放进背包更新。
    有一个方法:开始时把(n)个体积为(0)的物品放进背包,然后剩下的过程就是每次将若干个体积为(0)的物品替换为体积为(x)的物品。
    (f_0 = n * c_1),更新的时候比较(f_j)(f_{j - (i - 1)} + c_i - c_1),最后答案为(f_{n - 2})
    但是本题还要输出方案。这就要求dp的时候记录转移的前驱。利用这个我们可以计算出最终的树上的(n)个点在prufer序列上出现次数。
    然后利用这个贪心的思想构建这棵树(度数越小的放末尾,事实证明,把所有叶子结点放在末尾即可),注意根的特殊性(对于非根节点,在prufer序列出现次数 = 儿子数;对于根,在prufer序列出现次数 = 儿子数 - 1)。
    复杂度(mathcal O(n ^ 2))

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 3005, mod = 59393;
    int n, k, tot, a[N], c[N], f[N], g[N], d[N];
    void dfs (int x) {
    	for (int i = 1; i <= d[x]; ++i) {
            printf("%d %d
    ", x, ++tot);
            dfs(tot);
        }
    }
    int main () {
        scanf("%d%d", &n, &k);
        for (int i = 0; i <= k; ++i) {
        	scanf("%d", &a[i]);
    	}
    	for (int i = 0; i <= n; ++i) {
    		for (int j = k; ~j; --j) {
    			c[i] = c[i] * i % mod + a[j];
    			c[i] %= mod;
    		}
    	}
        if (n == 1) {
            printf("0 %d
    ", c[0]);
            return 0;
        }
        if (n == 2) {
            printf("1 %d
    ",2 * c[1]);
            printf("1 2
    ");
            return 0;
        }
    	f[0] = n * c[1];
    	for (int i = 2; i <= n; ++i) {
    		for (int j = i - 1; j <= n - 2; ++j) {
    			if (f[j] < f[j - (i - 1)] + c[i] - c[1]) {
    				f[j] = f[j - (i - 1)] + c[i] - c[1];
    				g[j] = j - (i - 1);
    			}
    		}
    	}
        printf("%d %d
    ", n - 1, f[n - 2]);
        for (k = n - 2; k; k = g[k]) {
        	d[++d[0]] = k - g[k];
    	}
    	sort(d + 1, d + d[0] + 1);
        ++d[1];
    	dfs(tot = 1);
        return 0;
    }
    
  • 相关阅读:
    迭代合并排序算法
    appendChild和insertBefore的区别
    使用定时器处理数组
    正则表达式 删除string首尾的空白
    图片滚动
    数组合并法(IE7性能优化)
    赋值取值+arguments
    条件预加载(conditional advanceloading)
    Just a Note~
    腾讯马拉松复赛第一场
  • 原文地址:https://www.cnblogs.com/psimonw/p/11509064.html
Copyright © 2020-2023  润新知