作业四,1001

题意:给定n个村子,以及n个村子之间的相互距离m,给n个村子修路,使它们联通,并知道有的村子已联通,写程序,求最少修多少米路,使村子都联通。

主要思路:使用并查集,图算法,建立从u到v的树,权值为d,把输入内容存在二维数组g【i】【j】里,将已有的顶点连线的权值设为零,建立树状图,对所有的村庄之间的距离进行排序,再利用并查集find函数和merge函数求出所求。

收获:对于数组不用全部写出,写一个下三角就行,因为从a到b与从b到a距离相等。具体事项代码有两种:

其一: for (i = 0; i < n; i++)
            for (j = 0; j <= i; j++) {
                e[cnt].u = i;
                e[cnt].v = j;
                e[cnt].d = g[i][j];
                cnt++;

}

其二:for(i=0;i<n;i++)

             for(j=0;j<n;j++){

             if(i>=j)continue;

               e[cnt].u = i;
                e[cnt].v = j;
                e[cnt].d = g[i][j];
                cnt++;

                  }

另外:find函数
可简写为:

int find(int x)
{
    if(x!=root[x])
        return find(root[x]);
    else return x;
}

解题过程同思路

AC代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;

#define MAXN 101

typedef struct edge {
    int u, v;
    int d;
} edge;

int g[MAXN][MAXN];
int root[MAXN];
int rank[MAXN];

edge e[5050];
int n;

void makeset(int m)
{
    int i;
    for (i = 0; i <= m; i++) {
        root[i] = i;
    }
}

int find(int x)
{
    if(x!=root[x])
        return find(root[x]);
    else return x;
}


void merge(int x, int y)
{
    int fx = find(x);
    int fy = find(y);

   if(fx!=fy)
    root[fx]=fy;
}

int cmp(edge a, edge b)
{
    return a.d < b.d;
}
int main()
{
    int i, j, k;
    int a, b, cnt, q;
    while (scanf("%d", &n) != EOF) {
        for (i = 0; i < n; i++) {
            for (j = 0; j < n; j++)
                scanf("%d", &g[i][j]);
        }

        scanf("%d", &q);
        for (i = 0; i < q; i++) {
            scanf("%d%d", &a, &b);
            g[a-1][b-1] = g[b-1][a-1] = 0;
        }

        cnt = 0;
        for (i = 0; i < n; i++)
            for (j = 0; j <= i; j++) {
                e[cnt].u = i;
                e[cnt].v = j;
                e[cnt].d = g[i][j];
                cnt++;
            }

        sort(e, e+cnt, cmp);

        int total = 0;
        makeset(n);
        for (i = 0; i < cnt; i++) {

            if (e[i].d == 0)
                merge(e[i].u, e[i].v);
            else if (find(e[i].u) != find(e[i].v)) {
                total += e[i].d;
                merge(e[i].u, e[i].v);
            }
        }

        printf("%d\n", total);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值