Prim 算法

23 篇文章 0 订阅
22 篇文章 0 订阅

测试样例:

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;
}

<加油> ^ _ ^

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值