大家都很强, 可与之共勉。
题面:
有一棵点数为 N 的树,树边有边权。给你一个在 0~ N 之内的正整
数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的
N-K个点染成白色 。 将所有点染色后,你会获得黑点两两之间的距
离加上白点两两之间的距离的和的受益。问受益最大值是多少。
其实就是:
有一棵N个点的边代权树,每个点都是白点,然后你要选择K个点将其染黑
一棵树的价值是白点两两间的距离和加黑点两两间的距离和,求最大化价值。
N<=2000,0<=K<=N
换句话说,i所考虑到的点的DFS序一定小于j所考虑到的点
于是我们就可以dpi,j表示子树i选了j个黑点,然后转移暴力枚举子树里选了几个黑点,复杂度还是O(n^2)的,关键在于如何去转移。
那么若不好转移,我们考虑设状态的问题。如果设他是子树i选了j个黑点,子树内的同色点对距离和的话,是不好转移的对吧……所以我们要把他们往子树外连的也考虑进来
我们可以这样做,假设我们把任意一对同色点之间的路径给标一下,那么dpi,j记录的就是,子树i选了j个黑点,子树内的所有被标过的路径权值和,这样就能转移了
一句话,就是改变一下状态定义,就能让他不仅考虑子树i内部的和,把子树外的延伸到子树内的那些边也考虑了。
#include "cstdio"
#include "cctype"
#include "cstring"
#include "algorithm"
#define abs(a) ((a) > 0 ? (a) : -(a))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define rep(i, m, n) for(register int i = (m); i <= (n); ++i)
#define res(i, m, n) for(register int i = (m); i >= (n); --i)
#define edges(u) for(register int i = head[u]; i; i = g[i].pre)
template <class T>
inline bool readIn(T &x) {
T flag = 1; char ch;
while(!(isdigit(ch = (char) getchar())) && ch != EOF) if( ch == '-' ) flag = -1;
if(ch == EOF) return false;
for(x = ch - 48; isdigit(ch = (char) getchar()); x = (x << 1) + (x << 3) + ch - 48);
x *= flag;
return true;
}
template <class T>
inline void write(T x) {
if (x > 9)
write(x / 10);
putchar(x % 10 + 48);
}
template <class T>
inline bool writeIn(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
write(x);
}
typedef long long LL;
#define MAXN 2005
class edge {
public:
int to, pre, w;
edge(int to = 0, int pre = 0, int w = 0) : to(to), pre(pre), w(w) { }
} g[MAXN << 1];
int n, k, u, v, w, ne, head[MAXN], siz[MAXN];
LL dp[MAXN][MAXN];
inline bool adde(int u, int v, int w) {
g[++ne] = edge(v, head[u], w), head[u] = ne;
return true;
}
inline void tree_dp(int u, int v, int w) {
res(i, siz[u], 0) {
rep(j, 1, siz[v])
dp[u][i + j] = max(dp[u][i + j], dp[u][i] + dp[v][j] + (LL) j * (k-j) * w + (LL) (siz[v]-j) * (n - k - siz[v] + j) * w );
dp[u][i] += dp[v][0] + (LL) siz[v] * (n - k - siz[v]) * w;
}
}
void dfs(int u, int f) {
siz[u] = 1;
edges(u) {
int v = g[i].to;
if(v ^ f) {
dfs(v, u);
tree_dp(u, v, g[i].w);
siz[u] += siz[v];
}
}
}
int main() {
readIn(n);readIn(k);
rep(i, 1, n - 1) readIn(u), readIn(v), readIn(w), adde(u, v, w), adde(v, u, w);
dfs(1, 0);
writeIn(dp[1][k]);
putchar('\n');
}