该题就是考的是如何花最小的代价使得一棵树划分开且不含后同类节点。
我们将边按从大到小的顺序排好序,然后就是看是否这条边能够使得两个同类的节点连在一起,如果能够的话,那么这条边就是我们要选择的划分边。首先将特征值保留起来,并通过并查集扩充给标记点。
代码如下:
#include <cstring> #include <cstdlib> #include <cstdio> #include <map> #include <algorithm> using namespace std; int N, M, set[100005], have[100005]; struct Edge { int x, y, fee; bool operator < (Edge t) const { return fee > t.fee; } }e[100005]; int find(int x) { return set[x] = x == set[x] ? x : find(set[x]); } void merge(int a, int b) { set[a] = b; if (have[a]) { have[b] = 1; } } int main() { int T, a, b, c; long long int sum; scanf("%d", &T); while (T--) { sum = 0; memset(have, 0, sizeof (have)); map<int,int>mp; scanf("%d %d", &N, &M); set[N-1] = N-1; for (int i = 0; i < N-1; ++i) { scanf("%d %d %d", &e[i].x, &e[i].y, &e[i].fee); set[i] = i; } for (int i = 0; i < M; ++i) { scanf("%d", &c); have[c] = 1; } sort(e, e + N - 1); for (int i = 0; i < N-1; ++i) { int a = find(e[i].x), b = find(e[i].y); if (have[a] && have[b]) { sum += e[i].fee; continue; } merge(a, b); } printf("%I64d\n", sum); } return 0; }