这道题是贪心。主要的难点在于合并路径压缩长度的策略。这里采用的方法是让一个个结点并入已经构建好的树中,并记录该结点接入树的位置、接入树到该结点的长度。模拟注意细节即可。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 using namespace std; 7 8 #define re register 9 #define rep(i, a, b) for (re int i = a; i <= b; ++i) 10 #define repd(i, a, b) for (re int i = a; i >= b; --i) 11 #define maxx(a, b) a = max(a, b); 12 #define minn(a, b) a = min(a, b); 13 #define LL long long 14 #define inf (1 << 30) 15 16 inline int read() { 17 int w = 0, f = 1; char c = getchar(); 18 while (!isdigit(c)) f = c == ‘-‘ ? -1 : f, c = getchar(); 19 while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ ‘0‘), c = getchar(); 20 return w * f; 21 } 22 23 const int maxn = 30 + 5, maxw = 100 + 5; 24 25 int N, M[maxn][maxn], link[maxn][maxw], l[maxn], ans; 26 27 int main() { 28 while (N = read()) { 29 memset(M, 0, sizeof(M)); 30 memset(link, 0, sizeof(link)); 31 memset(l, 0, sizeof(l)); 32 rep(i, 1, N-1) 33 rep(j, i+1, N) 34 M[i][j] = M[j][i] = read(); 35 l[2] = M[1][2]; 36 rep(i, 3, N) { 37 l[i] = M[1][i]; 38 int p = 2, q = 0; 39 while (1) { 40 int del = min((l[i] + l[p] - q - M[i][p]) >> 1, l[i]); 41 q += del; l[i] -= del; 42 if (link[p][q]) p = link[p][q], q = 0; else break; 43 } 44 while (link[p][q]) p = link[p][q], q = 0; 45 link[p][q] = i; 46 } 47 ans = 0; 48 rep(i, 2, N) ans += l[i]; 49 printf("%d\n", ans); 50 } 51 52 return 0; 53 }
将以上方法进行抽象简化,不再模拟,直接维护统计即可。
原文:https://www.cnblogs.com/ac-evil/p/10322307.html