刚看这道题时,我马上用了我习惯的prim算法去求最小生成树,但提交一看,超出内存限制。所以这道题建立二维数组必然超出内存空间的, 1 ≤ m ≤ 200000 and m-1 ≤ n ≤ 200000 可想而知,这个得多达。 于是乎,我马上转为并查集的Kruscal算法,因为这种算法只需要建立一维数组就可以了。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2988
这道题的题意就是让你求得最小生成树的和后,用总合减去这个值就得到结果了。
下面是我的AC代码:
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; struct path{ int x,y,z; }ss[200005]; int cmp(path i,path j) //从小到大排序 { return i.z<j.z; } int parent[200005],n,m,sum,ans; void make_set(int x) //初始化操作,一个节点的根节点是本身 { for(int i=0;i<=x;i++) //这里一定要从0开始,我本来以为应该从1开始的,因为n个节点嘛 parent[i]=i; //然后发现n的数据范围是从0开始的,所以这里必须如此... } int Find(int x) { if(x==parent[x]) //路径压缩+寻找根节点 return x; else parent[x]=Find(parent[x]); return parent[x]; } void Merge(int a) //合并+查找==并查集 { int L=Find(ss[a].x); int R=Find(ss[a].y); if(L!=R) { parent[L]=R; sum+=ss[a].z; } } int main() { while(scanf("%d%d",&n,&m)!=EOF&&(n||m)) { sum=ans=0; for(int i=1;i<=m;i++) { scanf("%d%d%d",&ss[i].x,&ss[i].y,&ss[i].z); ans+=ss[i].z; } sort(ss+1,ss+m+1,cmp); //注意起始地址 make_set(n); for(int i=1;i<=m;i++) Merge(i); printf("%d\n",ans-sum); } return 0; }
这算是最小生成树的水题应用了,要学会哦,不懂的话,去看看并查集和Kruscal算法是怎么回事!!!