200ms的板子,我尽力了,以我自己的能力没法再快了。。。
基于Kruskal的做法,跑了200ms,以我自己的能力没办法再快了,不过翻了几页评测列表发现我是最快的。。。我觉得应该会有更快的方法。
想法很简单,既然是最小生成树,把所有边按照边权升序排序,每次取一条最小权值的边,询问是否不在同一集合,如果不在,则最小生成树中就会有这条边,然后合并边所在的集合。生成树连接n个点,显然有n-1条边,所以开一个totedge来维护当前取到的边数,直到取完n-1条边为止。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define maxn 5005 6 #define maxm 200005 7 using namespace std; 8 struct Edge{ 9 int from,to,dis; 10 bool operator <(const Edge &rhs)const{ 11 return dis < rhs.dis; 12 } 13 }; 14 Edge edge[maxm]; 15 int father[maxm]; 16 int n,m; 17 int totedge = 0; 18 int k = 0; 19 int ans = 0; 20 inline int read(){ 21 int num = 0; 22 char c; 23 bool flag = false; 24 while ((c = getchar()) == ' ' || c == ' ' || c == ' '); 25 if (c == '-') 26 flag = true; 27 else 28 num = c - '0'; 29 while (isdigit(c = getchar())) 30 num = num * 10 + c - '0'; 31 return (flag ? -1 : 1) * num; 32 } 33 void init(){ 34 for (register int i=1;i<=m;i++) 35 father[i] = i; 36 } 37 int find(int x){ 38 if (father[x] == x) 39 return father[x]; 40 father[x] = find(father[x]); 41 return father[x]; 42 } 43 44 void merge(int x,int y){ 45 father[find(x)] = find(y); 46 } 47 48 int main(){ 49 n = read();m = read(); 50 for (register int i=1;i<=m;i++){ 51 edge[i].from = read(); 52 edge[i].to = read(); 53 edge[i].dis = read(); 54 } 55 sort(edge+1,edge+m+1); 56 init(); 57 while (totedge < n-1){ 58 if (find(edge[++k].from) != find(edge[k].to)){ 59 ans += edge[k].dis; 60 merge(edge[k].from,edge[k].to); 61 totedge++; 62 } 63 } 64 printf("%d ",ans); 65 return 0; 66 }