畅通工程之局部最小花费问题(修改加注释版)1prime 2暴力遍历 3kruskal(并查集)

https://blog.csdn.net/SYaoJun/article/details/101450783?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160733587819725271011092%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=160733587819725271011092&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-3-101450783.pc_search_result_no_baidu_js&utm_term=%E7%95%85%E9%80%9A%E5%B7%A5%E7%A8%8B%E4%B9%8B%E5%B1%80%E9%83%A8%E6%9C%80%E5%B0%8F%E8%8A%B1%E8%B4%B9%E9%97%AE%E9%A2%98&spm=1018.2118.3001.4449

https://www.bilibili.com/video/BV1b7411N798?p=45(讲并查集的)

#include<bits/stdc++.h>
//#include<stdlib.h>
#define MAX 101
#define INFINITY 65535

bool is_mark[MAX];//标记是否合并
int pathmatrirx[MAX][MAX];//所有路径长
int Dist[MAX];//当前连通量与其他地点的最短距离

int main() {
    int numofvertex;
    scanf("%d", &numofvertex);
    memset(pathmatrirx, 0x3f, sizeof(pathmatrirx));//带权图邻接矩阵初始化为无穷大,这里因为输入的边已经把图全塞满了,所有的点之间都有相互的边,所以不初始化为无穷大也可以,反正后面会输入修改

    int arcs = numofvertex * (numofvertex - 1) / 2;//所有的边数
    //输入边即道路修建成本
    for (int i = 0; i < arcs; i++) {
        int vil1, vil2, cost, state;
        scanf("%d%d%d%d", &vil1, &vil2, &cost, &state);
        //如果该道路已修好,则不计成本
        if (state == 1) {
            pathmatrirx[vil1 - 1][vil2 - 1] = pathmatrirx[vil2 - 1][vil1 - 1] = 0;
        }
            //否则,记录修建成本
        else {
            pathmatrirx[vil1 - 1][vil2 - 1] = pathmatrirx[vil2 - 1][vil1 - 1] = cost;
        }
    }

    //初始化Dist表
    for (int i = 0; i < numofvertex; i++) {
        Dist[i] = pathmatrirx[0][i];
    }

    //标记第一个点,且第一个点到自身的距离更改为0
    is_mark[0] = 0;
//    Dist[0] = 0;
    int sum = 0;
    for (int i = 0; i < numofvertex; i++) {
        int minpath = INFINITY;
        int order = -1;
        for (int j = 1; j < numofvertex; j++)//只记个次数,合并这些次,循环里面并不用i
        {
            if (minpath > Dist[j] && !is_mark[j]) {
                minpath = Dist[j];//选取目前离连通量最小的路径
                order = j;//记录离目前连通量最近的点的坐标
            }
        }
        //合并该点(标记该点)
        is_mark[order] = true;

        //每合并一个点,修改其他点到目前连通量的最小路径
        if (order != -1) {
            //最小路径求和
            sum += minpath;
            for (int j = 1; j < numofvertex; j++) {
                if (Dist[j] > pathmatrirx[order][j]) {
                    //如果有点距离当前连通量的距离小于原距离,修改Dist表
                    Dist[j] = pathmatrirx[order][j];
                }
            }
        }
    }
    printf("%d\n", sum);
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
int sum=0;
struct stu{
    int e=100000;//花费
    int flag=3;//flag无路,不可修建状态
}xx[101][101];
int n;
void fun(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int k=1;k<=n;k++){
                if(i==j||i==k||j==k) continue;
                if(xx[k][j].e>xx[k][i].e+xx[i][j].e)
                    xx[k][j].e=xx[k][i].e+xx[i][j].e;//各个点之间花费最少
            }
        }
    }
}
int main(){
    int a,b,c,d,min;
    cin>>n;
    for(int i=0;i<n*(n-1)/2;i++){
        cin>>a>>b>>c>>d;
        xx[a][b].flag=xx[b][a].flag=d;
        if(d==0)
            xx[a][b].e=xx[b][a].e=c;
        else if(d==1) xx[a][b].e=xx[b][a].e=0;
    }
    //寻找各个点之间最小花费
    fun();
    int sum=0;
    for(int i=2;i<=n;i++){
        sum=sum+xx[1][i].e;
        xx[1][i].e=0;
        fun();//这个解法时间复杂度比较大,
    }
    cout<<sum;
    return 0;
}

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10007;
struct edge{
    int u, v, cost, st;//起点,终点,花费,状态
    bool operator < (const edge a)const{
        return cost < a.cost;
    }
}E[N];
int root[N];
int find(int x){
    if(root[x] != x)
        root[x] = find(root[x]);
    return root[x];
}
int main(){
    int n;
    cin>>n;
    for(int i = 1; i <= n; i++){
        root[i] = i;
    }
    int len = n*(n-1)/2;
    for(int i = 0; i < len; i++){//先把st=1,已连接的归入一个集,防止后边+花费
        cin>>E[i].u>>E[i].v>>E[i].cost>>E[i].st;
        if(E[i].st == 1){
//            int u = find(E[i].u);
//            int v = find(E[i].v);
//            if(u != v){
//                root[v] = u;//将点归入同一个集
//            }
            E[i].cost=0;
        }
    }
    sort(E, E+len);
    int cost = 0;
    for(int i = 0; i < len; i++){ //先连的肯定是花费最小的,每个边都要检查一次,len次
        int u = find(E[i].u);
        int v = find(E[i].v);
        if(u != v){//判断这个边的起点和终点是否在一个集里,如果不是同一个集,即不构成回路,就连上(root归同)
            root[v] = u;
            cost += E[i].cost;
        }
    }
    cout<<cost<<endl;
    return 0;
}

另一个prime,这个比1简练些,其实里面有一些if判断条件应该不用加,不过我没测试

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
int x[101][101];
int val[101];
int mark[101];
int main()
{
    int dianshu,m,sum=0;
    cin >> dianshu;
    m= dianshu * (dianshu - 1) / 2;
    for(int i=1;i<=m;i++)
    {
        int start,end,e,r;
        cin >> start >> end >> e >> r;
        if(r==1)x[start][end]=0;
        else x[start][end]=e;
        x[end][start]=x[start][end];//双向图
    }
    mark[1]=1;//一定从第一个村庄开始,1为连上
    for(int i=1; i <= dianshu; i++)
    {
        val[i]=x[1][i];//距连通量的花费
    }
    int count=1;
    while(count < dianshu)//dianshu-1次
    {
        int min=INF;
        int f=0;
        for(int i=1; i <= dianshu; i++)
        {
            if(mark[i] == 0 && val[i] < min)
            {
                min=val[i];//最短距离
                f=i;
            }
        }
        mark[f]=1;
        count++;
        sum+=min;
        for(int i=1; i <= dianshu; i++)
        {
            if(mark[i] == 0 && val[i] >= x[f][i])
            {
                val[i]=x[f][i];//当有更小的权值时才会改变。
            }
        }
    }
    cout<<sum<<endl;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值