nyoj 38 布线问题(prim)

描述
南阳理工学院要进行用电线路改造,现在校长要求设计师设计出一种布线方式,该布线方式需要满足以下条件:
1、把所有的楼都供上电。
2、所用电线花费最少
输入
第一行是一个整数n表示有n组测试数据。(n<5)
每组测试数据的第一行是两个整数v,e.
v表示学校里楼的总个数(v<=500)
随后的e行里,每行有三个整数a,b,c表示a与b之间如果建铺设线路花费为c(c<=100)。(哪两栋楼间如果没有指明花费,则表示这两栋楼直接连通需要费用太大或者不可能连通)
随后的1行里,有v个整数,其中第i个数表示从第i号楼接线到外界供电设施所需要的费用。( 0<e<v*(v-1)/2 )
(楼的编号从1开始),由于安全问题,只能选择一个楼连接到外界供电设备。
数据保证至少存在一种方案满足要求。
输出
每组测试数据输出一个正整数,表示铺设满足校长要求的线路的最小花费。
样例输入
1
4 6
1 2 10
2 3 10
3 1 10
1 4 1
2 4 1
3 4 1
1 3 5 6
样例输出

4

思路:用最小生成树prim算法,需要注意的是,因为要有一个接外电源,花费最小的话,要找一个接外电源花费最小的点开始prim

#include<iostream>
#include<functional>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define INF 999999999
int n,m;
int Map[505][505],book[505];
int v[505],cas;
struct node{
    int place;
    int value;
    friend bool operator < (node n1,node n2){
        if(n1.value!=n2.value)
            return n1.value>n2.value;//优先队列,按照花费从小到大排
        else
            return n1.place>n2.place;
    }
}u,e;
int init(){
    int i,j;
    for(i=1;i<=n;i++){
        for(j=1;j<=n;j++){
            Map[i][j]=INF;
        }
    }
}
void Prim(int st){
    memset(book,0,sizeof(book));
    priority_queue<node>q;
    while(!q.empty()) q.pop();
    int i,j,sum;
    i=st;
    //printf("i=%d\n",i);
    for(j=1;j<=n;j++){
        if(Map[i][j]!=INF){
            u.place=j;
            u.value=Map[i][j];
            q.push(u);
           // printf("R u.p=%d u.v=%d\n",u.place,u.value);
        }
    }
    book[i]=1;
    cas=1;
    sum=v[i];
    while(!q.empty()){
        u=q.top();
        q.pop();
        if(book[u.place]==1)//已经走过的点不算
        continue;
           cas++;//记录走过点的个数
           sum+=u.value;//走过点的花费
           if(cas==n){
            printf("%d\n",sum);
            break;
           }
        book[u.place]=1;
      //  printf("C u.p=%d u.v=%d\n",u.place,u.value);
        i=u.place;
        for(j=1;j<=n;j++){
            if(Map[i][j]!=INF &&book[j]==0){
                e.place=j;
                e.value=Map[i][j];
                q.push(e);
              //  printf("R e.p=%d e.v=%d\n",e.place,e.value);
            }

        }

    }

}
int main(){
    int t,a,b,c;
    int i,j,mm;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        init();//先把地图初始化
        while(m--){
            scanf("%d%d%d",&a,&b,&c);
            if(Map[a][b]>c){
                 Map[a][b]=c;
                 Map[b][a]=c;
            }
        }
            mm=INF;
            for(i=1;i<=n;i++){
                scanf("%d",&v[i]);
                if(v[i]<mm){
                    mm=v[i];
                    j=i;
                }
            }
            Prim(j);//从接外电源花费最小的点


    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值