[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; }