soj3427: Dark road
http://acm.scu.edu.cn/soj/problem.action?id=3427
上周五太忙没做,本周多做一道,唉
题目简介:就是。。最小生成树的权值和比整棵树权值和少了多少。
因为本题数值太大,所以没法prim,就重新复习了一下kruskal最小生成树的方法,原理就是并查集,虽然当时学就是这样= =,不过不用并查集应该也可以,就是复杂了呗,自己实现一下去吧。
先讲并查集,就是看两棵树,找根,如果他们的根不同,那就没有相连,就不是一棵树的,这个时候就可以把一个的根当做另一个的根,这俩树就连在一起啦。
哎呦天,这个图我画的有点大,就是举例嘛,假设上图是我们找到的两个树,find(B)是否=find(F),查找B,F的根,AE并不相等,所以可以连起来,不会出现回路。
所以并查集就是:
int find(int a)
{
if(pre[a] == a)
return a;
else
return pre[a] = find(pre[a]); //注意这句
}
for(int i = 0;i <= n; i++)
pre[i] = i;
for(int i = 1;i <= m; i++)
{
int a = find(edge[i].x);
int b = find(edge[i].y);
if(a != b)
pre[a] = b;
}
然后Kruskal这道题就结束了:
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 200010
int pre[MAX];
struct map{
int x,y,len;
}edge[MAX];
bool cmp(map a, map b)
{
return a.len < b.len;
}
int find(int a)
{
if(pre[a] == a)
return a;
else
return pre[a] = find(pre[a]);
}
void Kruskal(int m,int n,int money)
{
int res = 0;
for(int i = 0;i <= m; i++)
pre[i] = i;
for(int i = 1;i <= n; i++)
{
int a = find(edge[i].x);
int b = find(edge[i].y);
if(a != b)
{
pre[a] = b;
res += edge[i].len;
}
}
printf("%d\n",money-res);
}
int main()
{
int m,n;
while(~scanf("%d%d",&m,&n))
{
int money = 0;
if(m==0 && n==0)
break;
for(int i = 1;i <= n; i++)
{
scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].len);
money += edge[i].len;
}
sort(edge+1,edge+1+n,cmp);
Kruskal(m,n,money);
}
return 0;
}