1982. Electrification Plan
Time limit: 0.5 second
Memory limit: 64 MB
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 ≤
k ≤
n ≤ 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
i ≠
j,
c
ii = 0.
Output
Output the minimum cost to electrify all the cities.
Sample
input | output |
---|---|
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
Problem Source: Open Ural FU Championship 2013
Tags:
graph theory
)
题意:
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;
}