测试样例:
6 10
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6
样例输出
1 3 1
3 6 4
6 4 2
3 2 5
2 5 3
15
代码实现:::
<第一遍>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int MAX=1000;
const int INF=0x3f3f3f3f; //定义一个极大的数
int array[MAX][MAX]; //二维数组存储点与点之间的权值w
int sumw=0; //计算最小数之和
void Prim(int n,int array[][MAX])
{
int l[MAX]; //保存未被归并的点的集合
int c[MAX]; //保存已经归并过的点的集合
bool just[MAX]= {false}; //判断是否归并过 false/true;
for(int i=1; i<=n; i++)
{
l[i]=array[1][i];
c[i]=1;
just[i]=false;
}
just[1]=true; //将归并过的点设为true第一个已经归并过去了;
for(int i=1; i<n; i++)
{
int min=INF;
int j=1;
for(int k=2; k<=n; k++) //从第二个开始
{
if((l[k]<min) && (!just[k])) //判断是否归并过这个点 just[k]是否归并过
{
min=l[k];
j=k;
}
}
cout<<c[j]<<" "<<j<<" "<<array[c[j]][j]<<endl;
sumw=sumw+array[c[j]][j];
just[j]=true; //将并过的 设为true
for(int k=2; k<=n; k++) //更新数值的 权值
{
if((array[j][k]<l[k])&&(!just[k]))
{
l[k]=array[j][k];
c[k]=j;
}
}
}
}
int main()
{
int n,m;
cin>>n>>m;
int i,j;
for(i=0; i<=n; i++)
for(j=0; j<=n; j++)
array[i][j]=INF; //初始化二维数组
int u,v,w;
for(i=0; i<m; i++)
{
cin>>u>>v>>w;
array[u][v]=w;
array[v][u]=w; 将二维数组中填入权值 w
}
Prim(n,array);
cout<<sumw<<endl;
return 0;
}
<第二遍>
#include <iostream>
#include<bits/stdc++.h>
#include <queue>
using namespace std;
int n,m;
queue<int> q;
const int MAXN=10000;
const int INF=0x3f3f3f3f;
int tu[MAXN][MAXN];
int sum;
void prim() {
sum=0;
int no[MAXN];
int at[MAXN];
bool just[MAXN];
memset(just,false,sizeof(n+1));
for(int i=1; i<=n; i++) {
no[i]=tu[1][i],
at[i]=1;
}
q.push(1);
just[1]=true;
for(int i=1; i<n; i++) {
int j=1;
int min=INF;
for(int k=2; k<=n; k++) {
if(no[k]<min&&!just[k]) {
min=no[k];
j=k;
}
}
q.push(j);
cout<<at[j]<<" "<<j<<" "<<tu[at[j]][j]<<endl;
sum=sum+tu[at[j]][j];
just[j]=true;
for(int k=2; k<=n; k++) {
if(tu[j][k]<no[k]&&!just[k]) {
no[k]=tu[j][k];
at[k]=j;
}
}
}
}
int main() {
int i,j;
cin>>n>>m;
for(i=0; i<=n; i++)
for(j=0; j<=n; j++)
tu[i][j]=INF;
int f,z,w;
for(i=0; i<m; i++) {
cin>>f>>z>>w;
tu[f][z]=w;
tu[z][f]=w;
}
cout<<endl;
prim();
// int k=q.size();
// for(int c=0;c<k;c++)
// {
// cout<<q.front()<<"->";
// q.pop();
// }
cout<<endl;
cout<<sum<<endl;
return 0;
}
主要体现了Prim算法的思想 归并点
核心代码::
void Prim(int n,int array[][MAX])
{
int l[MAX]; //保存未被归并的点的集合
int c[MAX]; //保存已经归并过的点的集合
bool just[MAX]= {false}; //判断是否归并过 false/true;
for(int i=1; i<=n; i++)
{
l[i]=array[1][i];
c[i]=1;
just[i]=false;
}
just[1]=true; //将归并过的点设为true第一个已经归并过去了;
for(int i=1; i<n; i++)
{
int min=INF;
int j=1;
for(int k=2; k<=n; k++) //从第二个开始
{
if((l[k]<min) && (!just[k])) //判断是否归并过这个点 just[k]是否归并过
{
min=l[k];
j=k;
}
}
cout<<c[j]<<" "<<j<<" "<<array[c[j]][j]<<endl;
sumw=sumw+array[c[j]][j];
just[j]=true; //将并过的 设为true
for(int k=2; k<=n; k++) //更新数值的 权值
{
if((array[j][k]<l[k])&&(!just[k]))
{
l[k]=array[j][k];
c[k]=j;
}
}
}
}
Prim 算法堆优化
最小生成树视屏连接 哔哩哔哩
以后常看。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>p; // pair 第一个值为 va 权值 后面一个用于存储 相关两的点。
vector<p>ve[999];// 将pair放入 vector 中存储起来 其中 ve[i]表示是两个定点的前一个。
int main()
{
int n,m,u,v,va;
int vis[999];
memset(vis,0,sizeof(vis));// 定义一个数组,用于判断是否访问过这一个顶点。
cin>>n>>m;
for(int i=1; i<=m; i++) {
cin>>u>>v>>va; // 录入想联系的两个边 和他门之间的权值.
// 一下两个是将数据放入里存储起来。
// u 前一个顶点 v 后一个顶点 va 表示 u-v之间的权值。
// 将pair放在优先队列里面让 以va权值的从小到大排序。
ve[u].push_back(p(va,v));
ve[v].push_back(p(va,u));
}
priority_queue<p ,vector<p>,greater<p> >pq; // 优先队列排序
vis[1]=1; // 从第一个顶点开始访问
for(int i=0; i<ve[1].size(); i++) {// ve[1][i].size() 查找以1 为首定点所有边,并且都放进优先队列里面。
pq.push(ve[1][i]);
}
int ans=0;
while(!pq.empty()) {
p now=pq.top();//new 一个now 为pair中的最前面的一个。
pq.pop();// 弹出这个值。
if(!vis[now.second]) {// 判断这个点是否访问过,没有的话、将其访问,并将这个点的权值加到答案里。
vis[now.second]=1;
ans+=now.first;
}
// 再次循环判断,now.second 也就将第一个边的 第二个点设为要研究的节点
for(int i=0; i<ve[now.second].size(); i++) {
if(!vis[ve[now.second][i].second]) // 判断这个节点,相关联的下一个节点是不是,遍历过,,如果没有将这个节点加入队列里面。
pq.push(ve[now.second][i]);
}
}
cout<<ans<<endl;
return 0;
}