最小生成树:kruskal和prim
kruskal:
首先对所有边按权值进行排序,依次选一条短的边,如果加入这条边且不能构成环,就把他加入到最小树里,怎么判断能不能构成环呢,可以把已经连通好了的点归为同一个集合里,每次加边的时候看这两点是否在一个集合里,不在一个集合里则这条边可加,因此可以用并查集来实现,时间复杂度为:(n个点,m条边,O(MlogM+MlogN),因为M一般比N大,所以为O(MlogM);
prim
首先任取一点入树。用一个数组来记录已生成的树到那些未加入树的顶点的距离,每次通过这个数组找离树最近的点,把这个点入树,然后通过这个点松弛其他为入树的点到新树的距离,在找最近点,在松弛,一直到把所有点都入树即可。借助堆优化,可以将复杂度降低到O(MlogN),下面分享一个自己写的裸的优先队列优化的prim
#include<stdio.h>
#include<vector>
#include<queue>
#include<algorithm>
#include<string.h>
using namespace std;
int prim();
int build();
struct node
{
int ri,qu;
bool operator<(const node &a)const
{
return qu>a.qu;
}
};
vector<node>w[1000];
int n,m,book[1000];
priority_queue<node>q;
int main()
{
int a,b,c;
while(~scanf("%d %d",&n,&m))
{
for(int i=0;i<=n;i++)
w[i].clear();
while(!q.empty())
{
q.pop();
}
memset(book,0,sizeof(book));
for(int i=0;i<m;i++)
{
scanf("%d %d %d",&a,&b,&c);
node t;
t.qu=c;
t.ri=b;
w[a].push_back(t);
t.ri=a;
w[b].push_back(t);
}
printf("%d\n",prim());
}
}
int build()
{
node t;
book[1]=1;
for(int i=0;i<w[1].size();i++)
{
t=w[1].at(i);
q.push(t);
}
return 0;
}
int prim()
{
int ans=1,sum=0;
build();
node re,pe;
while(!q.empty()&&ans<n)
{
re=q.top();
q.pop();
if(book[re.ri])
continue;
sum+=re.qu;
ans++;
book[re.ri]=1;
for(int i=0;i<w[re.ri].size();i++)
{
pe=w[re.ri].at(i);
if(book[pe.ri])
continue;
q.push(pe);
// printf("ha%d\n",pe.qu);
}//printf("%d %d %d %d\n",re.ri,sum,ans,q.empty());
}
return sum;
}
注意理解prim和dijikstra的区别:prim每次找离已生成的树集合最近的点,后者是找离原点最近的点,所以用数组dis来记录生成树到各个顶点的距离,也就是我们要记录的这个距离,并非为这个点到原点的最短距离,而是到任意一个已经入树的树顶点的最短距离。
Borg Maze
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 13547 | Accepted: 4414 | <