排序之后,我们首先拿到的是高度较高,权值较小的边,然后判断能不能到达这两个点(在搜索时处理),之后依次放高度较低的边(层层往下,知道最底层,什么也到不了)。高度相等的点不需要在考虑高度的影响,直接找最小的边,所以我们开始时先按高度在按权值排序,即分层最小生成树。
1 #include<cstdio>
2 #include<algorithm>
3 #include<queue>
4
5 using namespace std;
6 const int MAXN = 100010;
7 const int MAXM = 2000100;
8 struct Edge{
9 int x,y;
10 long long w;
11 }e[MAXM];
12 struct Node{
13 int nxt,to;
14 }t[MAXM];
15 int head[MAXN],h[MAXN],fa[MAXN];
16 bool vis[MAXN];
17 int n,m,cnt,ans=1;
18 long long sum;
19 queue<int>q;
20
21 void add(int u,int v,long long w)
22 {
23 ++cnt;
24 t[cnt].to = v;
25 t[cnt].nxt = head[u];
26 head[u] = cnt;
27 e[cnt] = (Edge){u,v,w};
28 }
29 int find(int x)
30 {
31 return x==fa[x]?x:fa[x]=find(fa[x]);
32 }
33 bool cmp(Edge a,Edge b) //先按高度排序,再按权值
34 {
35 return h[a.y]>h[b.y] || (h[a.y]==h[b.y] && a.w<b.w);
36 }
37 void bfs() //搜索出能够到达的点,和点的个数
38 {
39 q.push(1);
40 vis[1] = true;
41 while (!q.empty())
42 {
43 int u = q.front();
44 q.pop();
45 for (int i=head[u]; i; i=t[i].nxt)
46 {
47 int v = t[i].to;
48 if (!vis[v])
49 {
50 q.push(v);
51 vis[v] = true;
52 ans++;
53 }
54 }
55 }
56 printf("%d",ans);
57 }
58 void init()
59 {
60 scanf("%d%d",&n,&m);
61 for (int i=1; i<=n; ++i)
62 {
63 scanf("%d",&h[i]);
64 fa[i] = i; //初始化
65 }
66 for (int x,y,i=1; i<=m; ++i)
67 {
68 long long z;
69 scanf("%d%d%lld",&x,&y,&z);
70 if (h[x]>=h[y]) add(x,y,z); //排序时,结构体中是小的
71 if (h[y]>=h[x]) add(y,x,z);
72 }
73 }
74 void work()
75 {
76 sort(e+1,e+cnt+1,cmp);
77 for (int i=1; i<=cnt; ++i)
78 {
79 if (!vis[e[i].x] || !vis[e[i].y]) continue ; //不能到达,就continue
80 int rx = find(e[i].x);
81 int ry = find(e[i].y);
82 if (rx!=ry)
83 {
84 fa[rx] = ry;
85 sum += e[i].w;
86 }
87 }
88 printf(" %lld",sum);
89 }
90 int main()
91 {
92 init(); //初始化,输入
93 bfs(); //bfs求能到达的点
94 work(); //kruskal求距离
95 return 0;
96 }