7-10 公路村村通 (30分) 【最小生成树 Prim + Kruskal】

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:

输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。

输出格式:

输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。

输入样例:

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出样例:

12

 题解:

典型的最小生成树题目。算法有两个:Prim算法 和 Kruskal算法。本贴给出两个算法的代码。

Prime算法:

测试点 提示 结果 耗时 内存
0 sample换数字,各种回路判断

答案正确

 

4 ms 356 KB
1 M

答案正确

 

4 ms 424 KB
2 M达到N-1,但是图不连通

答案正确

 

4 ms 356 KB
3 最大N和M,连通

答案正确

 

20 ms 4224 KB
4 最大N和M,不连通

答案正确

 

16 ms 4324 KB
#include 
#include 
#include 

using namespace std;

int g[1002][1002]; // 图
int lowCost[1002]; // 点到已选集合的最短距离。0:已加入集合 
const int inf = 0x3f3f3f3f;

int main() {
    int n, m;
    int a, b, dis;
    int sum = 0, cnt;
    int minCost, minIndex; 
    
    memset(lowCost, 0, sizeof(lowCost));
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) // 初始化为最大值 
        for (int j = 1; j <= i; j++)
            g[i][j] = g[j][i] =  inf;
    for (int i = 0; i < m; i++){ // 构图 
        scanf("%d %d %d", &a, &b, &dis);
        g[a][b] = g[b][a] = dis; 
    }
    for (int i = 2; i <= n; i++)
        lowCost[i] = g[1][i];
    
    cnt = 1; // 加入集合的顶点数 
    for (int k = 1; k < n; k++){
        minCost = inf;
        minIndex = 0;
        for (int i = 2; i <= n; i++)
            if (lowCost[i]!=0 && lowCost[i]

 Kruskal算法:

测试点 提示 结果 耗时 内存
0 sample换数字,各种回路判断

答案正确

 

2 ms 356 KB
1 M

答案正确

 

3 ms 424 KB
2 M达到N-1,但是图不连通

答案正确

 

3 ms 484 KB
3 最大N和M,连通

答案正确

 

11 ms 424 KB
4 最大N和M,不连通

答案正确

 

7 ms 384 KB

 

#include 
#include 
#include 

using namespace std;

typedef struct Edge{ // 边 
    int u, v;
    int cost;
}Edge;

Edge edge[3002];
int father[1002];

bool cmp(Edge a, Edge b){ // 边,递增排列 
    return a.cost < b.cost;
}

int findFather(int x){ // 找集合编号 
    if (father[x] == x)
        return x;
    return findFather(father[x]);
}

int kruskal(int n, int m){
    int sum = 0, cnt = 0;
    int fu, fv;
    
    for (int i = 0; i < m; i++){
        fu = findFather(edge[i].u);
        fv = findFather(edge[i].v);
        if (fu != fv){
            father[fu] = fv; // 合并集合 
            cnt++;
            sum += edge[i].cost;
        }
    } 
    
    if (cnt == n-1) // OK 
        return sum;
    return -1; 
}

int main(){
    int n, m;
    
    scanf("%d %d", &n, &m);
    for (int i = 0; i < m; i++)
        scanf("%d %d %d", &edge[i].u, &edge[i].v, &edge[i].cost);
    
    sort(edge, edge+m, cmp);
    for (int i = 1; i <= n; i++) // 最初,每个顶点为一个独立集合 
        father[i] = i; 
    
    printf("%d", kruskal(n, m));
    
    return 0;
}

 

你可能感兴趣的:(7-10 公路村村通 (30分) 【最小生成树 Prim + Kruskal】)