HDU 3899

news/2024/11/24 13:53:52/

题意:给一个有N个顶点的树,每个顶点上有Ti个元素,树的每条边都有一个长度Ci。假设Cost_i为树中的每个元素到顶点i的距离之和。题目要求找出树中的一个顶点x,使得Cost_x最小。

解法:最近这类题目比较多,解法是通过两次dfs在O(n)的时间复杂度内求出每个点的Cost。具体来说,假设以顶点1为根对树进行dfs。第一次dfs计算出每个子树下面的元素个数Cunt和每个元素到顶点1的距离之和。第二次dfs再计算出每个顶点的Cost。第一次dfs比较简单,关键是第二次dfs。如果已经计算出顶点x的Cost_x,现在要计算和x相连的顶点y的Cost_y。假设一共有Total个元素,x和y相连的边的权值为Length,以顶点y为根的子树所包含的元素个数为Cunt_y。则可以看出:相对于Cost_x,有Total-Cunt_y个元素要多走Length的距离,有Cunt_y个元素要少走Length的距离。所以Cost_y=Cost_x-(Total-2*Cunt_y)*Length。所以可以通过第二遍dfs求出所有的Cost。

注意:由于n比较大,有比较极端的数据,递归深度会非常大。如果用递归写dfs,会RE,所以不能用递归。现在已经越来越多的题卡这一点了...

#include <stdio.h>
#include <memory.h>const int maxn = 100005;struct Graph {int hed[maxn], nxt[maxn*2], pnt[maxn*2], val[maxn*2];int idx;void init(int n) {memset(hed + 1, -1, n * 4);idx = 0;}void addedge(int x, int y, int v) {pnt[idx] = y; val[idx] = v; nxt[idx] = hed[x]; hed[x] = idx++;pnt[idx] = x; val[idx] = v; nxt[idx] = hed[y]; hed[y] = idx++;}
} gra;struct Node {int r, x, p;
} sta[maxn];int teams[maxn], total;
__int64 cunt[maxn], cost[maxn];void dfs_1() {int x, y, r, p, top = 0;sta[0].x = 1; sta[0].r = 0; sta[0].p = gra.hed[1];cunt[1] = teams[1];cost[1] = 0;while (true) {p = sta[top].p;if (p == -1) {top--;if (top >= 0) {p = sta[top].p;x = sta[top].x;y = gra.pnt[p];cunt[x] += cunt[y];cost[x] += cunt[y] * gra.val[p] + cost[y];sta[top].p = gra.nxt[p];} else {break;}} else {x = sta[top].x;r = sta[top].r;y = gra.pnt[p];if (y != r) {++top;cunt[y] = teams[y];cost[y] = 0;sta[top].r = x;sta[top].x = y;sta[top].p = gra.hed[y];} else {sta[top].p = gra.nxt[p];}}}
}void dfs_2() {int x, y, r, p, top = 0;sta[0].x = 1; sta[0].r = 0; sta[0].p = gra.hed[1];while (true) {p = sta[top].p;if (p == -1) {top--;if (top >= 0) {p = sta[top].p;sta[top].p = gra.nxt[p];} else {break;}} else {x = sta[top].x;r = sta[top].r;y = gra.pnt[p];if (y != r) {++top;cost[y] = cost[x] + (total - 2 * cunt[y]) * gra.val[p];sta[top].r = x;sta[top].x = y;sta[top].p = gra.hed[y];} else {sta[top].p = gra.nxt[p];}}}
}
/*
void dfs_1(int x, int r) {cost[x] = 0;cunt[x] = teams[x];for (int p = gra.hed[x]; p != -1; p = gra.nxt[p]) {int y = gra.pnt[p];if (y != r) {dfs_1(y, x);cunt[x] += cunt[y];cost[x] += cunt[y] * gra.val[p] + cost[y];}}
}
void dfs_2(int x, int r) {for (int p = gra.hed[x]; p != -1; p = gra.nxt[p]) {int y = gra.pnt[p];if (y != r) {cost[y] = cost[x] + (total - 2 * cunt[y]) * gra.val[p];dfs_2(y, x);}}
}
*/
int main() {int n, x, y, v;while (scanf("%d", &n) != EOF) {     total = 0;for (int i = 1; i <= n; i++) {scanf("%d", teams + i);total += teams[i];}gra.init(n);for (int i = 1; i < n; i++) {scanf("%d %d %d", &x, &y, &v);gra.addedge(x, y, v);}dfs_1();dfs_2();__int64 ans = cost[1];for (int i = 2; i <= n; i++) {if (cost[i] < ans)ans = cost[i];}printf("%I64d\n", ans);}return 0;
}



http://www.ppmy.cn/news/115556.html

相关文章

Hoj 1868 八数码问题

题目链接&#xff1a;http://acm.hit.edu.cn/hoj/problem/view?id1868 超时的写法&#xff1a;容易想到的是一遍搜索&#xff0c;把所有的状态都保留下来&#xff0c;我们只要建立0-8的全排列和0-362879的对应起来&#xff0c;就可以了。其中fact数组保留了以当前标号开始的全…

BZOJ 1399 Win

Description win 世界乒乓球比赛马上要拉开帷幕&#xff0c;你被邀请成为组委会成员&#xff0c;并且负责安排比赛赛程。比赛采取淘汰赛赛制&#xff0c;失败的一方将被直接淘汰。 你手上现在有一份各个队员近期的战况&#xff0c;战况包含任意两名队员的最近一次交手结果。你默…

ZCMU 1599

1599: 卡斯丁狗的炉石传说 卡斯丁狗喜欢玩一款叫做炉石传说双人对战的回合制的卡牌游戏&#xff08;喜欢前面再加两个字“极其”&#xff09;。游戏规则是这样的&#xff1a;游戏开始时每个玩家有一定量的生命值和一定数量的手牌和库牌&#xff0c;玩家可以使用自己手上的随从牌…

nyoj 998

nyoj 998 点击这里打开题目链接 给你一个数N,使得在1~N之间能够找到x使得x满足gcd&#xff08; x , N &#xff09; > M&#xff0c; 求解gcd(x,N)的和 思路&#xff1a;一开始想到暴力法做&#xff0c;超时 &#xff0c;后来借鉴学长经验AC&#xff1a; 大致思路: 用…

ZCMUOJ系列1829

ZCMU1829 题目 1829&#xff1a;十六进制转十进制 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 454 Solved: 169 [Submit][Status][Web Board] Description 从键盘输入一个不超过8位的正的十六进制数字符串&#xff0c;将它转换为正的十进制数后输出。 注&#xff1a;…

HZNUOJ 1960

没啥好说的&#xff0c;直接贴代码 #include <stdio.h> #include <math.h>int main () {int T, i;int h[4];//五位学长的身高 int level;//学姐等级 int darklight;//有无 黑照 double lightcnt;//学姐有几道光线 int kill;//竜死了几个学长 scanf("%d"…

hdu3999

/* 分析&#xff1a; 又是一个月黑风高的夜晚&#xff0c;终于。。。又可以刷题了&#xff0c;囧~&#xff0c; 十几分钟就能敲完的代码&#xff0c;白天愣是被打断了3、4次&#xff0c;终于敲完 了。。。 水~ 其实就是把这个树构成&#xff0c;然后遍历一遍输出&#xff0c;遍…

hdu 2899

题目意思&#xff0c;求函数的最小值。 很少见这种要高数方法解的题目&#xff0c;我一直以为要有三分法&#xff0c;但极值毕竟不是最值&#xff0c;看了题解才知道解法&#xff0c;这里就引用牛人的解法吧&#xff1a;用到一次求导求单调性&#xff0c;二次求导判断凹凸性&am…