1078题目链接:
1231题目链接:
普里姆算法(Prim)和克鲁斯卡尔算法(Kruskal)。
普里姆算法:
从任意一个结点出发,找出当前所连接结点全部路径中所最短的路径且满足下一个结点未访问过,直到把所有结点连接起来。
克鲁斯卡尔算法:
遍历所有边,找出当前未访问过且权值最小的边,判断两端结点是否已经相连,不相连,则连接起来,否则跳过该边。
普里姆算法更适合边稠密的图。
相反,克鲁斯卡尔算法更适合边稀疏的图。
1078(普里姆算法):
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 100 + 5;
const int MAX_INF = (1 << 31) - 1;
int G[MAXN][MAXN];
bool vis[MAXN];
int nowminedge[MAXN];
int main()
{
memset(vis, 0, sizeof(vis));
memset(G, -1, sizeof(G));
int n;
scanf("%d", &n);
for (int i = 0; i<n; i++)
{
for (int j = 0; j<n; j++)
scanf("%d", &G[i][j]);
nowminedge[i] = MAX_INF;
}
int pos = 0;
int nextnode = 0;
vis[0] = true;
int ans = 0;
for (int k = 1; k<n; k++)
{
int nowmin = MAX_INF;
for (int i = 0; i<n; i++)//更当前结点能到的任意结点的最小距离
{
if (!vis[i] && i != pos && G[pos][i]<nowminedge[i])
{
nowminedge[i] = G[pos][i];
}
}
for (int i = 0; i<n; i++)//找出其中最小的且未访问过的
{
if (!vis[i] && nowminedge[i]<nowmin)
{
nowmin = nowminedge[i];
nextnode = i;
}
}
pos = nextnode;//下一个结点
vis[nextnode] = true;
ans += nowmin;
}
printf("%d\n", ans);
return 0;
}
1231(克鲁斯卡尔算法):
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=100000+10;
int n,m;
long long ans;
struct Edge
{
int u,v,w;
}edge[MAXN];
int fa[MAXN];
void init()
{
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++)
fa[i]=i;
ans=0;
for(int i=0;i<m;i++)
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
}
bool cmp(Edge x,Edge y)
{
return x.w<y.w;
}
int find(int x)//并查集
{
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void solve()
{
sort(edge,edge+m,cmp);//排一下序
for(int i=0;i<m;i++)
{
int ru=find(edge[i].u);
int rv=find(edge[i].v);
if(ru==rv) //是否是一个连通块
continue;
else { //不是则连通,因为在未利用的边里面当前边是最小的。
ans+=edge[i].w;
fa[rv]=ru;
}
}
printf("%ld\n",ans);
}
int main()
{
init();
solve();
return 0;
}