[hdu5534]DP

题目原意:给一棵n个点的树添加边,给定度函数f(d)为一个点的度的函数,求所有点的度函数的和

思路:

  • 函数只与点的度有关,而与点无关,n个点的树有n-1条边,共产生2(n-1)个度,每个点至少有1个度。可以证明,一个合法的分配方式对应一棵树
  • 那么先对每个点各分配1个度,考虑把n-2个度分配给n个点
  • 由于结果跟点的编号无关,那么相当于把n-2个积木从前往后堆,每次有两种决策:(1)放在前面一堆上(2)另起一堆
  • 每一堆对应一个点,显然这种决策能得到任意的分配方式
  • 于是令dp[i][j]表示把i个度分最后1堆有j个的最大结果,那么两种决策分别转移到了:(1)+ (f[j+2]-f[j+1]) → dp[i+1][j+1](2)+ (f[2]-f[1]) → dp[i+1][1]
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define pb(x) push_back(x)
#define mp(x, y) make_pair(x, y)
#define all(a) (a).begin(), (a).end()
#define mset(a, x) memset(a, x, sizeof(a))
#define mcpy(a, b) memcpy(a, b, sizeof(b))
#define cas() int T, cas = 0; cin >> T; while (T --)
template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}
typedef long long ll;
typedef pair<int, int> pii;

#ifndef ONLINE_JUDGE
    #include "local.h"
#endif

const int N = 2016;

int dp[N][N], f[N];

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
    int n;
    cas() {
        cin >> n;
        for (int i = 1; i < n; i ++) {
            scanf("%d", f + i);
        }
        for (int i = 0; i <= n; i ++) {
            for (int j = 0; j <= n; j ++) {
                dp[i][j] = -1e9 - 7;
            }
        }
        dp[0][0] = f[1] * n;
        for (int i = 0; i < n - 2; i ++) {
            for (int j = 0; j <= i; j ++) {
                umax(dp[i + 1][1], dp[i][j] + f[2] - f[1]);
                umax(dp[i + 1][j + 1], dp[i][j] + f[j + 2] - f[j + 1]);
            }
        }
        int ans = 0;
        for (int i = 0; i <= n - 2; i ++) {
            umax(ans, dp[n - 2][i]);
        }
        cout << ans << endl;
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/jklongint/p/4928536.html