HDU3080

下午看到了这题,第一反应就是 MST,既然是 MST,可以用 Kruskal 快速地解决问题,记住在输入所有边之后,删除村庄时把边删除,我的方法是开一个数组 extextext[i]ext[i] 表示 ii 是否存在,在对边结构体排序的时候,把不存在的边通通放到后面去,这样,当 Kruskal 过程中,找到一个不存在的边时,就退出,这样会节省比较多的时间。

并查集初始化的时候要全部初始化,以防出现不用的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

using namespace std;

const int MAX = 210;
int n, cnt, ret;
int p[MAX], rank[MAX];
bool ext[MAX];

struct Edge {
int from;
int to;
int weight;
bool operator<(const Edge& edge) const {
if (ext[from] == false || ext[to] == false) return false;
if (ext[edge.from] == false || ext[edge.to] == false) return true;
return weight < edge.weight;
}
} edge[MAX * MAX];

void Init() {
for (int i = 0; i < 210; i++) {
p[i] = i;
rank[i] = 0;
}
}

void Link(int x, int y) {
if (rank[x] < rank[y])
p[x] = y;
else {
p[y] = x;
if (rank[x] == rank[y]) rank[x]++;
}
}

int Find(int x) {
if (p[x] != x) p[x] = Find(p[x]);
return p[x];
}

void Union(int x, int y) { Link(Find(x), Find(y)); }

bool Kruskal() {
sort(edge, edge + cnt);
int done = 0;
Init();
for (int i = 0; i < cnt && done < n - 1; i++) {
if (ext[edge[i].from] == false || ext[edge[i].to] == false) break;
if (Find(edge[i].from) != Find(edge[i].to)) {
done++;
ret += edge[i].weight;
Union(edge[i].from, edge[i].to);
}
}
if (done == n - 1)
return true;
else
return false;
}

int main() {
int t;
int x, y, w;
int nn, ee, m;
scanf("%d", &t);
while (t--) {
cnt = 0;
ret = 0;
memset(ext, 0, sizeof(ext));
scanf("%d%d", &nn, &ee);
n = nn;
for (int i = 0; i < nn; i++) ext[i] = true;
for (int i = 0; i < ee; i++) {
scanf("%d%d%D", &x, &y, &w);
edge[cnt].from = x;
edge[cnt].to = y;
edge[cnt].weight = w;
cnt++;
}
scanf("%d%d", &nn, &ee);
for (int i = n; i < n + nn; i++) ext[i] = true;
n += nn;
for (int i = 0; i < ee; i++) {
scanf("%d%d%D", &x, &y, &w);
edge[cnt].from = x;
edge[cnt].to = y;
edge[cnt].weight = w;
cnt++;
}
scanf("%d", &m);
n -= m;
for (int i = 0; i < m; i++) {
scanf("%d", &x);
ext[x] = false;
}
if (Kruskal())
printf("%d\n", ret);
else
printf("what a pity!\n");
}
return 0;
}