太原理工大学2021数据结构课程设计(构造可以使n个城市连接的最小生成树)

太原理工大学2021软件学院数据结构课程设计第二题(构造可以使n个城市连接的最小生成树)核心代码 Java+c(2021.6.6)

声明:这里只是给出核心代码

核心代码指程序的计算部分,不是完整程序

题目背景:P3366 【模板】最小生成树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目

题目描述

如题,给出一个向图,求出最小生成树,如果该图不连通,则输出 orz

输入格式

第一行包含两个整数 N,M,表示该图共有 N 个结点和 M 条无向边。

接下来 M 行每行包含三个整数xi,yi,zi,表示有一条长度为zi的无向边连接结点 xi,yi.

输出格式

如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz

输入输出样例

**输入 **

4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3

输出 #1

7

最小生成树背景知识

1.最小生成树的代价指最小生成树各边长度之和

Kruscal算法代码

import java.io.*;
import java.util.Arrays;
import java.util.Comparator;

/**
 * @see 图论 Kruscal https://www.luogu.com.cn/problem/P3366 https://www.acwing.com/solution/content/30279/
 */
public class Main {

    static class Edge {
        int a, b, w;

        public Edge(int a, int b, int w) {
            this.a = a;
            this.b = b;
            this.w = w;
        }
    }

    static final int N = 100010;
    static int n, m;
    static int[] p;
    static Edge[] edges;

    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    static int nextInt() throws Exception {
        in.nextToken();
        return (int) in.nval;
    }

    static String next() throws Exception {
        in.nextToken();
        return in.sval;
    }

    /**
     * 并查集find模板
     * @param x 当前连通块的点
     * @return
     */
    static int find(int x) {
        if (p[x]!=x){
            p[x] = find(p[x]);
        }
        return p[x];
    }

    static int kruskal() {
        Arrays.sort(edges, Comparator.comparingInt(a -> a.w));
        for (int i = 1; i <= n; i++) {
            p[i] = i;
        }
        int res = 0, count = 0;
        for (int i = 0; i < m; i++) {
            int a = edges[i].a, b = edges[i].b, w = edges[i].w;
            a = find(a);
            b = find(b);
            if (a != b) {
                p[a] = b;
                res += w;
                count++;
            }
        }
        //判断是否连通
        return count < n - 1 ? -1 : res;

    }

    public static void main(String[] args) throws Exception {
        n = nextInt();
        m = nextInt();
        edges = new Edge[m];
        p = new int[n + 1];

        for (int i = 0; i < m; i++) {
            int a = nextInt();
            int b = nextInt();
            int c = nextInt();
            edges[i] = new Edge(a, b, c);

        }
        int ans = kruskal();
        if (ans==-1){
            System.out.println("impr");
        }else {
            System.out.println(ans);
        }

    }


}

Kruscal算法代码(c++)

#include<bits/stdc++.h>
using namespace std;
typedef int ll;
const ll N=2e5+10,INF=0x3f3f3f3f;
ll m,n,p[N];
struct edge{
    ll a,b,w;
    bool operator<(const edge &e)const {     //重载小于号,使其按权重排序; 
        return w<e.w;
    }
}es[N];
ll find(ll x)
{
    if(p[x]!=x)p[x]=find(p[x]);
    return p[x];
}
int main()
{
    cin>>n>>m;
    for(ll i=0;i<m;i++)
    {
        ll a,b,w;
        cin>>a>>b>>w;
        es[i]={a,b,w};
    }
    sort(es,es+m);
    for(ll i=1;i<=n;i++) p[i]=i;    //初始化父节点; 
    ll res=0,cnt=0;                 //res是最小生成树的权重之和;
                                    //cnt是树中的边的数目,用于判断是否存在生成树; 
    for(ll i=0;i<m;i++)
    {
        ll a=es[i].a,b=es[i].b,w=es[i].w;
        a=find(a),b=find(b);        //如果ab不连通则联通; 
        if(a!=b)
        {
            p[a]=b;
            res+=w;
            cnt++;                  //边的数目加一; 
        }
    }
    if(cnt<n-1)cout<<"impossible"<<endl;  //边数小于n-1条说明无生成树; 
    else cout<<res<<endl;
}

Prim算法代码(Java)

package Acwing858Prim算法求最小生成树;

import java.io.*;
import java.util.Arrays;

/**
 * @see 图论 最小生成树 Prim https://www.acwing.com/solution/content/38312/ https://www.luogu.com.cn/problem/P3366
 */
public class PrimClass {
    static final int INF = 9999;
    static int[][] ad;
    static int[] dist;
    static int n, m;
    static boolean[] st;

    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    static int nextInt() throws Exception {
        in.nextToken();
        return (int) in.nval;
    }

    static int prim() {
        Arrays.fill(dist, INF);
        int res = 0;
        for (int i = 0; i < n; i++) {
            int t = -1;
            for (int j = 1; j <= n; j++) {
                if (!st[j] && (t == -1 || dist[j] < dist[t])) {
                    t = j;
                }
            }
            if (i > 0 && dist[t] == INF) {
                return INF;
            }
            if (i > 0) {
                res += dist[t];
            }
            for (int j = 1; j <= n; j++) {
                dist[j] = Math.min(dist[j], ad[t][j]);
            }
            st[t] = true;

        }
        return res;
    }

    public static void main(String[] args) throws Exception {
        n = nextInt();
        m = nextInt();
        dist = new int[n+1];
        ad = new int[n+1][n+1];
        st = new boolean[n+1];
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if (i == j) {
                    ad[i][j] = 0;
                } else {
                    ad[i][j] = INF;
                }
            }
        }

        while (m-- > 0) {
            int a = nextInt();
            int b = nextInt();
            int c = nextInt();
            ad[a][b] = Math.min(ad[a][b], c);
//-------------无向图-----------------------------
            ad[b][a]= ad[a][b];
//-----------------------------------------------
        }
        int ans = prim();
        if (ans == INF) {
            System.out.println("orz");
        } else {
            System.out.println(ans);
        }


    }


}

Prim(c++)

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 510;
int g[N][N];//存储图
int dt[N];//存储各个节点到生成树的距离
int st[N];//节点是否被加入到生成树中
int pre[N];//节点的前去节点
int n, m;//n 个节点,m 条边

void prim()
{
    memset(dt,0x3f, sizeof(dt));//初始化距离数组为一个很大的数(10亿左右)
    int res= 0;
    dt[1] = 0;//从 1 号节点开始生成 
    for(int i = 0; i < n; i++)//每次循环选出一个点加入到生成树
    {
        int t = -1;
        for(int j = 1; j <= n; j++)//每个节点一次判断
        {
            if(!st[j] && (t == -1 || dt[j] < dt[t]))//如果没有在树中,且到树的距离最短,则选择该点
                t = j;
        }

        st[t] = 1;// 选择该点
        res += dt[t];
        for(int i = 1; i <= n; i++)//更新生成树外的点到生成树的距离
        {
            if(dt[i] > g[t][i] && !st[i])//从 t 到节点 i 的距离小于原来距离,则更新。
            {
                dt[i] = g[t][i];//更新距离
                pre[i] = t;//从 t 到 i 的距离更短,i 的前驱变为 t.
            }
        }
    }
}

void getPath()//输出各个边
{
    for(int i = n; i > 1; i--)//n 个节点,所以有 n-1 条边。

    {
        cout << i <<" " << pre[i] << " "<< endl;// i 是节点编号,pre[i] 是 i 节点的前驱节点。他们构成一条边。
    }
}

int main()
{
    memset(g, 0x3f, sizeof(g));//各个点之间的距离初始化成很大的数
    cin >> n >> m;//输入节点数和边数
    while(m --)
    {
        int a, b, w;
        cin >> a >> b >> w;//输出边的两个顶点和权重
        g[a][b] = g[b][a] = min(g[a][b],w);//存储权重
    }

    prim();//求最下生成树
    //getPath();//输出路径
    return 0;
}

再次强调,以上只是核心代码,同学们要根据核心代码,自己编写完整的程序

完整程序应该是这样

在这里插入图片描述

刷题不迷路,欢迎关注博主的git题集,这里有最详细的分类,最经典的例题和最全面的注释


在这里插入图片描述

感兴趣的同学可以赏个star吗:算法刷题集git地址 题目源码地址

  • 6
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值