Agri-Net(POJ 1258)

Agri-Net

Time Limit: 1000MS    Memory Limit: 10000K

Description
Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He needs your help, of course.
Farmer John ordered a high speed connection for his farm and is going to share his connectivity with the other farmers. To minimize cost, he wants to lay the minimum amount of optical fiber to connect his farm to all the other farms.
Given a list of how much fiber it takes to connect each pair of farms, you must find the minimum amount of fiber needed to connect them all together. Each farm must connect to some other farm such that a packet can flow from any one farm to any other farm.
The distance between any two farms will not exceed 100,000.

Input
The input includes several cases. For each case, the first line contains the number of farms, N (3 <= N <= 100). The following lines contain the N x N conectivity matrix, where each element shows the distance from on farm to another. Logically, they are N lines of N space-separated integers. Physically, they are limited in length to 80 characters, so some lines continue onto others. Of course, the diagonal will be 0, since the distance from farm i to itself is not interesting for this problem.

Output
For each case, output a single integer length that is the sum of the minimum length of fiber required to connect the entire set of farms.

Sample Input
4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0

Sample Output
28

Source
http://poj.org/problem?id=1258

这个题是简单的最小生成树,并且是此分类所用的模板题
样例图示:
Agri-Net样例

AC的代码

C语言版

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 110   //最多顶点数
#define MAX 0x3f3f3f3f  //模拟无穷大
int map[N][N];  //存储各顶点间的权值
int flag[N];    //标记是否已纳入树
int dis[N];     //已纳入点和其余各点的最小权值
int prim(int n)        //普利姆函数
{
    int i, j;
    int now;    //记录新纳入的点
    int min;    //记录新纳入的点到其余已纳入的点的最小权值
    int sum = 0;    //最小生成树权值和
    memset(dis, MAX, sizeof(dis));  //初始化dis数组为无穷大
    memset(flag, 0, sizeof(flag));  //初始化flag数组,0表示此点未被纳入
    /*这里随机选取了1号点为初始时被纳入的顶点*/
    for(i = 1; i <= n; i++)
        dis[i] = map[1][i];     //与1号点与其他点的权值存入dis数组
    dis[1] = 0;         //一号点到其本身的权值为0
    flag[1] = 1;        //标记为已纳入

    for(i = 1; i < n; i++){         //除去初始时随机纳入的点还有n-1个点应被纳入
        now = min = MAX;            //初始为无穷大表示两点间无通路
        for(j = 1; j <= n; j++){    //遍历
            if(flag[j] == 0){
                if(dis[j] < min){   //寻找与已纳入各点权值最小的点
                    now = j;
                    min = dis[j];
                }
            }
        }
        if(now == MAX)      //若now等于max,则证明所有与初始时纳入的点连通的点已全被纳入
            break;
        sum += min;     //将找到的点纳入并标记
        flag[now] = 1;
        for(j = 1; j <= n; j++){
            /*
                遍历比较之前纳入点到未纳入点的权值的最小值
                与刚纳入点到未纳入点的权值
                并用dis[j]存储新的最小值
            */
            if(flag[j] == 0)
                if(dis[j] > map[now][j])
                    dis[j] = map[now][j];
        }
    }
    if(i == n)      //若i等于n则证明已经建立最小生成树
        return sum;
    else
        return -1;
}
int main(void)
{
    int i, j, k;
    int n;      //顶点数
    while(scanf("%d", &n) != EOF){
        for(i = 1; i <= n; i++)
            for(j = 1; j <= n; j++)
                scanf("%d", &map[i][j]);  //输入i和j之间的距离
        if((k = prim(n)) != -1) //调用prim函数
            printf("%d\n", k);
    }
    return 0;
}

Python版

# encoding: utf-8
import sys
N = 110   #最多顶点数
MAX = 0x3f3f3f3f  #模拟无穷大
mapV = [[0 for i in range(N)] for i in range(N)] #存储各顶点间的权值
flag = [0]    #标记是否已纳入树
flag = flag * N
dis = [0]     #已纳入点和其余各点的最小权值
dis = dis * N
def prim(n):        #普利姆函数
    #now记录新纳入的点
    #min记录新纳入的点到其余已纳入的点的最小权值
    sum = 0    #最小生成树权值和
    dis = [MAX]     #初始化dis列表为无穷大
    dis = dis * N
    flag = [0]    #初始化flag列表,0表示此点未被纳入
    flag = flag * N
    '''这里随机选取了1号点为初始时被纳入的顶点'''
    for i in range(1, n+1):
        dis[i] = mapV[1][i]     #与1号点与其他点的权值存入dis列表
    dis[1] = 0         #一号点到其本身的权值为0
    flag[1] = 1        #标记为已纳入
    for i in range(1, n):        #除去初始时随机纳入的点还有n-1个点应被纳入
        now = min = MAX;            #初始为无穷大表示两点间无通路
        for j in range(1, n+1):    #遍历
            if flag[j] == 0:
                if dis[j] < min:   #寻找与已纳入各点权值最小的点
                    now = j
                    min = dis[j]
        if now == MAX:      #若now等于max,则证明所有与初始时纳入的点连通的点已全被纳入
            break
        sum += min     #将找到的点纳入并标记
        flag[now] = 1
        for j in range(1, n+1):
            '''
                遍历比较之前纳入点到未纳入点的权值的最小值
                与刚纳入点到未纳入点的权值
                并用dis[j]存储新的最小值
            '''
            if flag[j] == 0:
                if dis[j] > mapV[now][j]:
                    dis[j] = mapV[now][j]
    if i == n-1:      #若i等于n则证明已经建立最小生成树
        return sum
    else:
        return -1
#n: 顶点数
while True:
    try:
        n = int(input())
    except:
        break
    for i in range(1, n+1):
        mapV[i] = list(map(int, sys.stdin.readline().split()))  #输入i和j之间的距离
        mapV[i].insert(0, 0)
    k = prim(n)
    if  k != -1:  #调用prim函数
        print(k)
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值