1075: 求最小生成树(Prim算法)

题目描述
求出给定无向带权图的最小生成树。图的定点为字符型,权值为不超过100的整形。在提示中已经给出了部分代码,你只需要完善Prim算法即可。

题目所给代码如下:

#include<iostream>
using namespace std;
typedef struct
{
    int n;
    int e;
    char data[500];
    int edge[500][500];
}Graph;

typedef struct
{
    int index;
    int cost;
}mincost;

typedef struct
{
    int x;
    int y;
    int weight;
}EDGE;


typedef struct
{
    int index;
    int flag;
}F;

void create(Graph &G,int n ,int e)
{
    int i,j,k,w;
    char a,b;
    for(i=0;i< n;i++)
    cin>>G.data[i];
    for(i=0;i< n;i++)
    for(j=0;j< n;j++)
    {
        if(i==j)
        G.edge[i][j]=0;
        else
        G.edge[i][j]=100;
    }

    for(k=0;k< e;k++)
    {
        cin>>a;
        cin>>b;
        cin>>w;
        for(i=0;i< n;i++)
        if(G.data[i]==a) break;
        for(j=0;j< n;j++)
        if(G.data[j]==b) break;

        G.edge[i][j]=w;
        G.edge[j][i]=w;
    }
        G.n=n;
        G.e=e;
}

void Prim(Graph &G,int k)
{

}

int main()
{
    Graph my;
    int n,e;
    cin>>n>>e;
    create(my,n,e);
    Prim(my,0);
    return 0;
}

输入
第一行为图的顶点个数n第二行为图的边的条数e接着e行为依附于一条边的两个顶点和边上的权值

输出
最小生成树中的边。

样例输入

6
10
ABCDEF
A B 6
A C 1
A D 5
B C 5
C D 5
B E 3
E C 6
C F 4
F D 2
E F 6

样例输出

 (A,C)(C,F)(F,D)(C,B)(B,E)

题目有点难,参考教材284页,建议反复看几遍B站李春葆数据结构课程中prime算法一节

#include<iostream>
using namespace std;
const int maxn=100;
const int INF=101;
typedef struct
{
    int n;
    int e;
    char data[500];
    int edge[500][500];
}Graph;

typedef struct
{
    int index;
    int cost;
}mincost;

typedef struct
{
    int x;
    int y;
    int weight;
}EDGE;


typedef struct
{
    int index;
    int flag;
}F;

void create(Graph &G,int n ,int e)
{
    int i,j,k,w;
    char a,b;
    for(i=0;i< n;i++)
    cin>>G.data[i];
    for(i=0;i< n;i++)
    for(j=0;j< n;j++)
    {
        if(i==j)
        G.edge[i][j]=0;
        else
        G.edge[i][j]=100;
    }

    for(k=0;k< e;k++)
    {
        cin>>a;
        cin>>b;
        cin>>w;
        for(i=0;i< n;i++)
        if(G.data[i]==a) break;
        for(j=0;j< n;j++)
        if(G.data[j]==b) break;

        G.edge[i][j]=w;
        G.edge[j][i]=w;
    }
        G.n=n;
        G.e=e;
}
//参考教材284页
void Prim(Graph &G,int v)
{
    int lowcost[maxn];
    int MIN;
    int closest[maxn],i,j,k;
    //closest[i] 表示V-U集合中i点到U的最小边
    //类似学生与学校的距离,学生是点,学校是一个区域
    //如closest[j]=v 表示j到与集合U中的v点相连
    //形成的距离是最短距离,距离是lowcost[j]
    for(i=0;i<G.n;i++)
    //初始时U集合中只有v一个结点
    //V-U集合中各点到U集合的边权,都是 起点v到i 的距离
    //即V-U集合中各点只与集合U中的v相连
    {
        lowcost[i]=G.edge[v][i];
        closest[i]=v;
    }
    for(i=1;i<G.n;i++)
    {
        MIN=INF;
        for(j=0;j<G.n;j++)
        {
            if(lowcost[j]!=0&&lowcost[j]<MIN)
            //找最短距离,lowcost[j]表示集合U-V中的顶点j到集合U的最短距离
            //如果lowcost[j]==0,则表示j在集合U中
            {
                MIN=lowcost[j];
                k=j;
            }
        }
        printf("(%c,%c)",G.data[closest[k]],G.data[k]);
        lowcost[k]=0;//表示k点已移动到集合U中
        for(j=0;j<G.n;j++)
        //以集合U中新加入点k为中介点
        //更新集合U-V中各点到k的距离(集合U-V中各点到集合U的距离)
        //若有更短距离,则更新
        {
            if(lowcost[j]!=0&&G.edge[k][j]<lowcost[j])
            //①若j不在集合U中
            //②k到集合U-V中j点的距离小于j点到集合U的距离
            //则更新数据
            {
                lowcost[j]=G.edge[k][j];
                closest[j]=k;
            }
        }
    }
}

int main()
{
    Graph my;
    int n,e;
    cin>>n>>e;
    create(my,n,e);
    Prim(my,0);
    return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Prim算法是一种解加权无向连通图的最小生成树的贪心算法。它从一个顶点开始,逐步扩展生成树的大小,直到生成整个最小生成树为止。 以下是Prim算法的实现过程: 1. 从图任选一个顶点作为起始点,将该顶点加入生成树。 2. 以该顶点为起始点,找出与其相邻的所有边,并将这些边加入到一个优先队列。 3. 从队列取出一条边(权值最小),如果该边的另一个端点不在生成树,则将其加入生成树,并将该点作为下一个起始点。 4. 重复步骤2和步骤3,直到生成树包含所有的顶点。 以下是Prim算法的C++代码实现: ```c++ #include <iostream> #include <vector> #include <queue> using namespace std; const int MAXN = 1005; const int INF = 1e9; int n, m; int vis[MAXN], dis[MAXN]; vector<pair<int, int>> G[MAXN]; //G[i]存储以i为起点的所有边 int Prim(int s) { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; //小根堆 fill(dis, dis + n + 1, INF); //初始化 dis[s] = 0; pq.push(make_pair(0, s)); int sum = 0; while (!pq.empty()) { int u = pq.top().second; pq.pop(); if (vis[u]) continue; vis[u] = 1; sum += dis[u]; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i].first; int w = G[u][i].second; if (!vis[v] && w < dis[v]) { dis[v] = w; pq.push(make_pair(dis[v], v)); } } } return sum; } int main() { cin >> n >> m; for (int i = 1; i <= m; i++) { int u, v, w; cin >> u >> v >> w; G[u].push_back(make_pair(v, w)); G[v].push_back(make_pair(u, w)); } int ans = Prim(1); //从1号点开始生成最小生成树 cout << ans << endl; return 0; } ``` 其,dis[i]表示以i为起点的最小边权值,vis[i]表示是否已经访问过i节点。优先队列pq存储以访问过的点为起点的边,每次取出队首元素时,若该点已经被访问过,则弃掉该边,否则将该点加入生成树,并将该点的所有边加入队列

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值