[洛谷P1268]树的重量

原题传送门

方法一

这道题是贪心。主要的难点在于合并路径压缩长度的策略。这里采用的方法是让一个个结点并入已经构建好的树中,并记录该结点接入树的位置、接入树到该结点的长度。模拟注意细节即可。

 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 }

方法二

将以上方法进行抽象简化,不再模拟,直接统计即可。

 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;
24 
25 int n, e[maxn][maxn], ans;
26 
27 int main() {
28     while (n = read()) {
29         ans = 0;
30         rep(i, 1, n-1)
31             rep(j, i+1, n)
32                 e[i][j] = e[j][i] = read();
33         rep(i, 2, n) {
34             int l = INF;
35             rep(j, 1, i-1)
36                 l = min(l, e[1][i] - ((e[1][i] + e[1][j] - e[i][j]) >> 1));
37             ans += l;
38         }
39         printf("%d\n", ans);
40     }
41 
42     return 0;
43 }

 

转载于:https://www.cnblogs.com/ac-evil/p/10322307.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值