prim 算法 按点算,适合于点少的情况

邻接矩阵,时间复杂度 o(n^2)

//PTA公路村村通 
#include<iostream>
#include<cstdio>
using namespace std;
const int INF = 0x3fffffff;
const int MAXV = 1005;
int G[MAXV][MAXV], d[MAXV];//G存两个城镇直接的距离,d存已标记点到此点的最短距离 
bool vis[MAXV];//vis存是否被标记过 
int prim(int n)
{
	int ans = 0;//边权最小值 
	fill(vis,vis+MAXV,false);
	fill(d, d + MAXV, INF);
	d[1] = 0;//从第一个城镇开始 
	for (int i = 0; i < n; i++)//n个点,循环n次 
	{
		int u = -1, Min = INF;//Min存放最小d[u],u点的d[u]最小 
		for (int j = 1; j <= n; j++)//寻找未访问点中最小d[] 
		{
			if (vis[j] == false && d[j] < Min)
			{
				u = j;
				Min = d[j];
			}
		}
		if (u == -1)return -1;//不连续,无法连成一棵树 
		vis[u] = true;//标记已访问 
		ans += d[u];
		for (int k = 1; k <= n; k++)//更新与u点连接的最优值 
		{
			//k未访问&&k能到达u&&u为中介点使k离集合更短 
			if (vis[k] == false && G[u][k] != INF&&G[u][k] < d[k])
				d[k] = G[u][k];
		}
	}
	return ans;
}
int main()
{
	int n, m, i, a, b, c, ans;//n代表城镇个数,m代表路径个数 
	while(scanf("%d %d",&n,&m)!=EOF&&n)
	{
	    fill(G[0], G[0] + MAXV*MAXV, INF);//G初始化为没有任何路径连通 
	for (i = 0; i < m; i++)
	{
		cin >> a >> b >> c;//输入两个城镇与权值 
		G[a][b] = G[b][a] = c;
	}
	ans = prim(n);
	cout << ans << endl;//ans存最后结果 
	}
	return 0;
}

邻接表法,时间复杂度 o(nlogn+e)

//PTA公路村村通 
#include<iostream>
#include<cstdio>
#include<vector> 
using namespace std;
const int INF = 0x3fffffff;
const int MAXV = 1005;
struct node
{
	int v,dis;
};//v为边的目标顶点,dis为边权 
vector<node> s[MAXV];
int d[MAXV];//d存已标记点到此点的最短距离 
bool vis[MAXV];//vis存是否被标记过 
int prime(int n)
{
	int ans = 0;//边权最小值 
	fill(vis,vis+MAXV,false);
	fill(d, d + MAXV, INF);
	d[1] = 0;//从第一个城镇开始 
	for (int i = 0; i < n; i++)//n个点,循环n次 
	{
		int u = -1, Min = INF;//Min存放最小d[u],u点的d[u]最小 
		for (int j = 1; j <= n; j++)//寻找未访问点中最小d[] 
		{
			if (vis[j] == false && d[j] < Min)
			{
				u = j;
				Min = d[j];
			}
		}
		if (u == -1)return -1;//不连续,无法连成一棵树 
		vis[u] = true;//标记已访问 
		ans += d[u];
		for (int k = 0; k < s[u].size(); k++)//更新与u点连接的最优值 
		{
			int v=s[u][k].v;//通过邻接表直接获得u能到达的顶点v 
			//k未访问&&u为中介点使k离集合更短 
			if (vis[v] == false && s[u][k].dis < d[v])
				d[v] = s[u][k].dis;
		}
	}
	return ans;
}
int main()
{
	int n, m, i, a, b, c, ans;//n代表城镇个数,m代表路径个数 
	while(scanf("%d %d",&n,&m)!=EOF&&n)
	{
		for(i=0;i<MAXV;i++)//清空所有邻接表 
		{
			s[i].clear();
		}
	for (i = 0; i < m; i++)
	{
		node t;
		cin >> a >> b >> c;//输入两个城镇与权值 
		t.v=b;
		t.dis=c;
		s[a].push_back(t);
		t.v=a;
		t.dis=c;
		s[b].push_back(t);
	}
	ans = prime(n);
	cout << ans << endl;//ans存最后结果 
	}
	return 0;
}

kruskal 算法 适用于边少的情况

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int MAXN=1005; 
const int N=105; 
struct node
{
	int x, y, z;//x,y代表端点,z权值 
}s[MAXN];
int father[N];//并查集数组 
int findfather(int v)//并查集函数 
{
	if (v == father[v])return v;
	else 
	{
		int f = findfather(father[v]);
		father[v]=f;//压缩路径 
		return f;
	}
}
bool cmp(node a, node b)//权值小的放前面 
{
	return a.z < b.z;
}
int kruskal(int n,int m)//n个顶点,m边数 
{
	int i,num=0,a,b,ans=0;//num存选择的边数,ans存最小权值 
	for (i = 1; i <= n; i++)//并查集初始化 
		father[i] = i;
	sort(s + 1, s + m + 1, cmp);//按边的权值从小到大排序 
	for (i = 1; i <= m; i++)
		{
			a = findfather(s[i].x); b = findfather(s[i].y);
			if(a!=b)//不在一个集合 
			{
				father[b] = a;//合并集合 
				num++;//道路数量相加 
				ans += s[i].z;//权值 
				if (num == n - 1)break;//边数等于顶点减 1时结束 
			}
		}
		if(num!=n-1)return -1;//无法连通时返回-1 
		else return ans;
}
int main()
{
	int m, n, i, sum;
	while (scanf("%d %d", &n,&m)!=EOF && n && m)//n代表城镇个数,m代表路的个数 
	{
		for (i = 1; i <= m; i++)
		{
			scanf("%d %d %d", &s[i].x, &s[i].y, &s[i].z);
		}
		sum=kruskal(n,m);//sum为最小权值 
		printf("%d\n", sum);
	}
	return 0;
}