ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【CCF-CSP】最优灌溉

2021-08-22 16:36:59  阅读:200  来源: 互联网

标签:include dist int 距离 集合 INF 最优 CCF CSP


算法(Prim算法)

时间复杂度:\(O(n^2)\)
Prim算法伪代码

dist[i] = 正无穷
for (i = 0; i < n; i ++ )
	t 找到集合外部距离最近的点
	用 t 更新其他点到集合的距离
	st[t] = true

时间复杂度为\(O(V^2)\),V为顶点个数,与边数E无关,所以适合边稠密的图

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 1010, INF = 0x3f3f3f3f;

int n, m;    //n个点 m条边
int g[N][N]; //记录图中点到点之间的距离
int dist[N]; //记录每个点到最小生成树集合的距离
bool st[N];  //记录每个点是否在最小生成树集合中

int prim() {
    LL res = 0; //记录最小生成树边权之和
    
    //第一步:将所有点到集合的距离初始化为正无穷
    memset(dist, INF, sizeof dist);
    
    //第二步:任取一个点加入集合,初始化距离为0,利用当前点更新其他点到集合的距离
    for (int i = 0; i < n; i ++ ) {
        int t = -1;
        for (int j = 1; j <= n; j ++ )
            //若当前点不在集合 且 还没有加入点或者当前点到集合的距离更小
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        
        //如果不是第一个点并且到集合距离为无穷 则该点不存在
        if (i && dist[t] == INF) return INF;
        
        //将该点加入集合
        if (i) res += dist[t];
        st[t] = true;
        
        //利用当前点更新其他点到集合的距离
        for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);
    }
    return res;
}

int main() {
    cin >> n >> m;
    
    //初始化图
    memset(g, INF, sizeof g);
    while (m -- ) {
        int a, b, c;
        cin >> a >> b >> c;
        g[a][b] = g[b][a] = min(g[a][b], c);
    }
    
    LL res = prim();
    
    cout << res << endl;
    
    return 0;
}

算法2(Kruskal算法)

时间复杂度:\(O(m\log m)\)
Kruskal算法伪代码:

将所有边按权重从小到大排序 //O(mlogm)

枚举每条边a,b 权重是c //O(m)
if a b 不连通
	把这条边加入集合  //并查集时间复杂度O(1)

适用于边稀疏而顶点较多的图。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010, M = 100010;

int n, m;

struct Edge{
    int a, b, c;
    
    bool operator< (const Edge& E)const {
        return c < E.c;
    }
}edge[M];

//并查集
int p[N];
int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int kruskal() {
    //第一步:将所有边按权重大小排序
    sort(edge, edge + m);
    
    //并查集初始化
    for (int i = 1; i <= n; i ++ ) p[i] = i;
    
    //第二步:枚举每条边,若不连通,则把这条边加入最小生成树
    int res = 0, cnt = 0; //res为最小生成树边权之和 cnt为最小生成树边的数量
    for (int i = 0; i < m; i ++ ) {
        int a = edge[i].a, b = edge[i].b, c = edge[i].c;
        
        a = find(a), b = find(b);
        //如果不连通,则加入这条边
        if (a != b) {
            p[a] = b;
            cnt ++;
            res += c;
        }
    }
    
    if (cnt < n - 1) return -1; //没有最小生成树
    else return res;
}

int main() {
    scanf("%d%d", &n, &m);
    
    for (int i = 0; i < m; i ++ ) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        edge[i] = {a, b, c};
    }
    
    int res = kruskal();
    
    printf("%d\n", res);
    return 0;
}

标签:include,dist,int,距离,集合,INF,最优,CCF,CSP
来源: https://www.cnblogs.com/I-am-Sino/p/15172640.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有