Prim算法
内置类型pair
介绍
pair的应用
将两个数据合成一个数据(元组),方便使用。如当一个函数需要返回两个数据,可以返回pair类型。pair的实现是一个结构体。有两个成员:first,second。
make_pair函数
template pair make_pair(T1 a, T2 b) { return pair(a, b); }
usage1: std::make_pair(1, 1.1)
灵活的方式,会自动进行类型转换,T1为int,T2为double
usage2: std::pair<int, float>(1, 1.1);
指定T1,T2类型
使用样例
pair<int, double> p1; //使用默认构造函数
pair<int, double> p2(1, 2.4); //用给定值初始化
pair<int, double> p3(p2); //使用p2初始化p3
p1.first=1;
p1.second=2.5;
cout<<p1.first<<" "<<p1.second<<endl;
p2=make_pair(1, 1.2);
简化申明
有时候会觉得使用起来很繁琐,可以使typedef简化申明:
typedef pair<string, string> author;
author zuozhe1("Jim", "Green");
author zuozhe2("Jack", "Brown");
string s1="W.Bush";
string s2="George";
author newone;
newone=make_pair(s1, s2);
排序
作为系统内置类型,pair自带排序能力:先比较第一个参数,如果第一个参数相同再比较第二个参数。你可以使用greater<pair<T1, T2> >
或less<pair<T1, T2> >
来控制排序方式。
朴素Prim复杂度为O(N^2),此Prim算法使用了优先队列优化,复杂度介于O(eloge)~O(nloge)之间,鼓励你使用模板题与Kruskal对比计算效率。
一般而言,朴素Prim适用于点少边多
的情况,Kruskal适用于点多边少
的情况。
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef pair<int, int> pii;
const int maxn=5e3+5, maxm=4e5+5;
int n, m, head[maxn], nxt[maxm], v[maxm], w[maxm], cnt, dis[maxn];
bool tag[maxn]; //标记点是否被加入MST
void add(int x, int y, int z) { cnt++, v[cnt]=y, w[cnt]=z, nxt[cnt]=head[x], head[x]=cnt; }
int prim(int s)
{
memset(dis, 0x7f, sizeof(dis)); //清空dis数组
priority_queue<pii, vector<pii>, greater<pii> > Q; //小根堆
int num=1, ans=0; //num统计加入MST的点的数量,ans为MST边权和
tag[s] = true;
for(int i=head[s]; i; i=nxt[i])
if(v[i]!=s) Q.push(make_pair(w[i], v[i])), dis[v[i]]=min(dis[v[i]], w[i]);
while(!Q.empty() && num!=n)
{
while(!Q.empty() && tag[Q.top().second]) Q.pop();//忽略已加入MST的点
if(Q.empty()) break;
int x=Q.top().second; //最小dis
tag[x]=true, ans+=Q.top().first, num++; //加入mst
Q.pop();
for(int i=head[x]; i; i = nxt[i]) //使用x松弛与当前MST相连点的dis值
if(!tag[v[i]] && dis[v[i]]>w[i]) Q.push(make_pair(w[i], v[i])), dis[v[i]]=w[i];
}
if (num!=n) return -1;
else return ans;
}
int main(void)
{
scanf("%d%d", &n, &m);
for(int i=1, x, y, z; i<=m; i++) //x, y, z放在for内定义可以省一行空间
scanf("%d%d%d", &x, &y, &z), add(x, y, z), add(y, x, z);
int ans=prim(1);
if(ans!=-1) printf("%d\n", ans);
else printf("orz\n");
return 0;
}