题目描述
发展采矿业当然首先得有矿井,小 FF 花了上次探险获得的千分之一的财富请人在岛上挖了 nnn 口矿井,但他似乎忘记考虑的矿井供电问题……
为了保证电力的供应,小 FF 想到了两种办法:
- 在这一口矿井上建立一个发电站,费用为 vvv(发电站的输出功率可以供给任意多个矿井)。
- 将这口矿井与另外的已经有电力供应的矿井之间建立电网,费用为 ppp。
小 FF 希望身为「NewBe_One」计划首席工程师的你帮他想出一个保证所有矿井电力供应的最小花费。
输入格式
第一行一个整数 n,表示矿井总数。
第 2∼n+1 行,每行一个整数,第 i个数 vi 表示在第 i 口矿井上建立发电站的费用。
接下来为一个 n×n 的矩阵 p,其中 p{i,j} 表示在第 i口矿井和第 j 口矿井之间建立电网的费用(数据保证pi,j=pj,i,pi,i=0)。
输出格式
输出仅一个整数,表示让所有矿井获得充足电能的最小花费。
样例
样例输入
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
样例输出
9
样例解释
小 FF 可以选择在 4号矿井建立发电站然后把所有矿井都建立电网,总花费是 3+2+2+2=9
分析:这道题原来用的克鲁斯卡尔算法(最小生成树+最小v[i]),在LOJ上最多得了50分。
其实它可能出现一个矿井修电网还不如修电站的情况,故改用Prim算法
#include<bits/stdc++.h> using namespace std; int a[1000][1000],v[1000]; int dis[10000]; bool book[10000]; #define inf 1e12; int main() { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>v[i]; a[i][n+1]=v[i]; a[n+1][i]=v[i]; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j]; memset(book,0,sizeof book); for(int k=1;k<=n+1;k++) { dis[k]=a[1][k]; } book[1]=1; int ans=0; for(int k=1;k<=n;k++) { long long mins=inf; int minj; for(int j=1;j<=n+1;j++) { if(!book[j]&&dis[j]<mins) { mins=dis[j]; minj=j; } } book[minj]=1; ans+=dis[minj]; for(int j=1;j<=n+1;j++) if(book[j]==0&&dis[j]>a[minj][j]) dis[j]=a[minj][j]; } cout<<ans; }