您的位置:首页 > 编程语言 > C语言/C++

ural 1982. Electrification Plan -最小生成树

2016-11-26 18:29 525 查看

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 cij 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 {cij} (0 ≤
cij ≤ 105). It is guaranteed that
cij =
cji, cij > 0 for
i ≠ j, cii = 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
Tags: graph theory  (

hide tags for unsolved problems
)

题意:
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息