ural 1982. Electrification Plan -最小生成树

1982. Electrification Plan

Time limit: 0.5 second
Memory limit: 64 MB

Some country has n cities. The government has decided to electrify all these cities. At first, power stations in k different cities were built. The other cities should be connected with the power stations via power lines. For any cities i, j it is possible to build a power line between them in c ij roubles. The country is in crisis after a civil war, so the government decided to build only a few power lines. Of course from every city there must be a path along the lines to some city with a power station. Find the minimum possible cost to build all necessary power lines.

Input

The first line contains integers n and k (1 ≤ kn ≤ 100). The second line contains k different integers that are the numbers of the cities with power stations. The next n lines contain an n × n table of integers { c ij} (0 ≤ c ij ≤ 10 5). It is guaranteed that c ij = c ji , c ij > 0 for ij, c ii = 0.

Output

Output the minimum cost to electrify all the cities.

Sample

inputoutput
4 2
1 4
0 2 4 3
2 0 5 2
4 5 0 1
3 2 1 0
3
Problem Author: Mikhail Rubinchik
Problem Source: Open Ural FU Championship 2013


题意:
n个城市,其中k个城市有发电站,问,怎么才能让每个城市都有电,并且花费最小


解题思路
每个有发电站的城市都能做出一个最小生成树来,然后好几个最小生成树。但是这样不好写
我们设置一个超级发电站,一开始所有发电站都与之相连,让超级发电站当这课树的根,
这样,既达到了将好几棵树变成一棵树的目的,又使得发电站与发电站之间边的权值不会被加进结果去
然后用 kruskl 算法做最小生成树,
这里注意,因为是从边权值最小开始,权值最小的边的节点的父亲可能都不是超级发电站,
所以后期遇到一个以超级发电站为父亲节点的,要让不是超级发电站为父亲节点的连进去。(有点乱,见代码)


代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <functional>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 110;
int n,k;
int fa[maxn];
int suroot;
int root[maxn];
void init(){
    for(int i = 0;i<maxn;i++){
        ///让所有发电站都以超级发电站为父亲
        ///这样就不会把发电站与发电站之间连线了,相当于多个生成树了
        if(root[i]) fa[i] = suroot;
        else
            fa[i] = i;
    }
}
struct edge{
    int u,v,cost;
}e[maxn*maxn];

bool comp(const edge& e1,const edge& e2){
    return e1.cost < e2.cost;
}

int findp(int x){
    int xp = x;
    while(fa[xp] != xp){
        xp = fa[xp];
    }
    int nowx = x,newx;
    while(fa[nowx] != xp){
        newx = fa[nowx];
        fa[nowx] = xp;
        nowx = newx;
    }
    return xp;
}

int main()
{
    scanf("%d%d",&n,&k);
    for(int i = 0;i<k;++i){
        scanf("%d",&suroot);///指定一个超级发电站,只要是发电站就好,无所谓哪个
        root[suroot] = 1;
    }
    init();///初始化父亲
    int E = 0;///边的编号,一共E条边,下标到E-1
    for(int i = 1;i<=n;++i){
        for(int j=1;j<=n;++j){
            int t;
            scanf("%d",&t);
            e[E].u = i;
            e[E].v = j;
            e[E].cost = t;
            E++;
        }
    }

    sort(e,e+E,comp);

    int res = 0;
    for(int i = 0; i<E; i++){
        edge te = e[i];
        int fu = findp(te.u),fv = findp(te.v);
        if(fu == fv) continue;
///因为可能最小的边连得不是超级发电站,
///所以当我们遇到一个父亲是超级发电站的时候,
///再让超级发电站当 根 父亲
        if(fu == suroot){
            fa[fv] = fu;
            res += te.cost;
        }
        else if(fv == suroot){
            fa[fu] = fv;
            res += te.cost;
        }
        else{
            fa[fu] = fv;
            res += te.cost;
        }
    }
    printf("%d",res);
    return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值