1.并查集
用法:一个方便归类的算法。。。
将一个复杂的图转换成一个公共父节点的图(如图所示)
具体代码:
int find(int x) //并查集
{
int r=x,i=x,temp;
if (tree[r]==r)
return r;
while (tree[r]!=r) //r 找到 最.根节点
r=tree[r];
while (i!=r) //全部变成跟节点
{
temp=tree[i]; //temp 临时变量
tree[i]=r;
i=temp;
}
return r;
}
2.sort排序
头文件:algorithm
基础用法:从小到大排序:sort(a,a+n); (n指数组a的大小)
高尚用法:sort(a,a+n,compare);
其中compare是个bool函数(注意:不能用 '<=' 或 '>=')
bool compare(node e1,node e2) //sort排序---比较函数
{
return e1.weight<e2.weight;
}
3.克鲁斯卡尔算法
好了。。。终于到重点了。。。
首先,记录是以边记录
然后
用sort从小到大排序一波边的权值大小
接着
从小到大依次选边
如果这条边与原来选择的边构成了环,就不选这条(continue)
ps:是否构成环可用并查集完成
代码献上:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct node
{
int from,end,weight;
};
const int maxSize=200000;
int n,m;
int tree[maxSize+5];
node edge[maxSize+5];
bool compare(node e1,node e2) //sort排序---比较函数
{
return e1.weight<e2.weight;
}
int find(int x) //并查集
{
int r=x,i=x,temp;
if (tree[r]==r)
return r;
while (tree[r]!=r) //r 找到 最.根节点
r=tree[r];
while (i!=r) //全部变成跟节点
{
temp=tree[i]; //temp 临时变量
tree[i]=r;
i=temp;
}
return r;
}
void Kruskal()
{
int i,sum,tot,fx,fy;
tot=1;
sum=0;
i=0;
while (tot<n)
{
fx=find(edge[i].from);
fy=find(edge[i].end);
if (fx!=fy)
{
tree[fx]=fy; //并查集合并 (这里是最.根节点的合并!!!)
tot++;
sum+=edge[i].weight;
}
i++;
}
printf("%d\n",sum);
}
int main()
{
int i,x,y,z;
freopen("a.txt","r",stdin);
scanf("%d%d",&n,&m);
for (i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
edge[i].from=x; edge[i].end=y; edge[i].weight=z;
}
sort(edge,edge+m,compare);
for (i=1;i<=n;i++)
tree[i]=i;
Kruskal();
return 0;
}