题目链接:https://ac.nowcoder.com/acm/problem/212004
到主站看:https://blog.csdn.net/weixin_43346722/article/details/109689050
题目
众所周知,题目名称与题面没有任何关系。
你发现了一道 div2 的 A 题,下面是这道题的题面:
给定一张 个点,
条边的无向联通图和一个常数
,每个点拥有点权
,每条边拥有边权
,现在他决定保留一些边,这样将剩余部分连通块,牛牛的目标是使得每个剩余的连通块的点权和都是
的倍数,同时最小化被保留的边的权值和。
输入
第一行两个正整数
接下来一行 个正整数,第
个正整数表示节点
的权值是
接下来 行,每行
个正整数,表示一条连接
边权为
的边。
输出
输出一行一个正整数最小的权值和。
样例输入1
5 2 1 0 1 1 1 1 2 5 1 4 3 2 3 2 2 5 1
样例输出1
6
样例解释1
选择
样例输入2
10 3 1 3 4 2 1 6 2 3 5 6 1 2 2 1 4 1 2 3 3 2 6 3 2 10 2 5 6 4 5 7 4 6 8 3 6 9 1
样例输出2
12
样例解释2
选择
数据范围
思路
这道题是一道爆搜。
因为原来就是一棵树,那我们就可以让任意一个点为根,进行 dfs 爆搜。
对于每一个子树,如果它自己已经可以单独存在,那它就没有必要与它的父亲连边。
否则,就要连边,与父亲变成新的连通块。
代码
#include<cstdio> #include<queue> using namespace std; vector <int> to[1000001], size[1000001]; int n, k, x, y; long long z, sum[1000001], ans; void dfs(int now, int father) { for (int i = 0; i < to[now].size(); i++) if (father != to[now][i]) { dfs(to[now][i], now); sum[now] = (sum[now] + sum[to[now][i]]) % k; if (sum[to[now][i]]) ans += size[now][i];//如果这个子树不能单独形成连通块就要连接 } } int main() { scanf("%d %d", &n, &k); for (int i = 1; i <= n; i++) { scanf("%lld", &sum[i]); sum[i] %= k; } for (int i = 1; i < n; i++) { scanf("%d %d %lld", &x, &y, &z); to[x].push_back(y); size[x].push_back(z); to[y].push_back(x); size[y].push_back(z); } dfs(1, 0); printf("%lld", ans); return 0; }