发展采矿业当然首先得有矿井,小 F 花了上次探险获得的千分之一的财富请人在岛上挖了 n 口矿井,但他似乎忘记了考虑矿井供电问题。
为了保证电力的供应,小 F 想到了两种办法:
- 在矿井 i 上建立一个发电站,费用为 vi(发电站的输出功率可以供给任意多个矿井)。
- 将这口矿井 i 与另外的已经有电力供应的矿井 j 之间建立电网,费用为 pi,j。
小 F 希望你帮他想出一个保证所有矿井电力供应的最小花费方案。
输入格式
第一行包含一个整数 n,表示矿井总数。
接下来 n 行,每行一个整数,第 i 个数 vi 表示在第 i 口矿井上建立发电站的费用。
接下来为一个 n×n 的矩阵 P,其中 pi,j 表示在第 i 口矿井和第 j 口矿井之间建立电网的费用。
数据保证 pi,j=pj,i,且 pi,i=0。
输出格式
输出一个整数,表示让所有矿井获得充足电能的最小花费。
数据范围
1≤n≤300,
0≤vi,pi,j≤1e5输入样例:
4 5 4 4 3 0 2 2 2 2 0 3 3 2 3 0 4 2 3 4 0
输出样例:
9
难度:中等 时/空限制:1s / 64MB 总通过数:3714 总尝试数:5252 来源:《信息学奥赛一本通》 算法标签
挑战模式
很有意思的题,不是传统的最小生成树,对于每个点,有两种方式,第一种是连接一个有电的矿井,第二种是自己建立一个发电站,在求最小生成树的前提下,如果按照他的方式,代码的实现程度非常难,那么就需要转化,自己建立一个发电站需要的花费可以看成连接一个有点矿井,那么就可以把每个点自己建立发电站看成他们都去连接一个超级发电站,这样就抽相处n+1个点,然后就是最小生成树prim
#include <iostream> #include <algorithm> #include <cstring> using namespace std; constexpr int N=305,INF=0x3f3f3f3f; int n; int g[N][N],dist[N]; bool st[N]; int prim(){ int ans=0; memset(dist,0x3f,sizeof dist); dist[0]=0; for(int i=0;i<n+1;i++){ int t=-1; for(int j=0;j<=n;j++){ if(!st[j]&&(t==-1||dist[t]>dist[j])){ t=j; } } ans+=dist[t]; for(int j=0;j<=n;j++){ dist[j]= min(dist[j],g[t][j]); } st[t]= true; } return ans; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&g[0][i]); g[i][0]=g[0][i]; } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&g[i][j]); } } printf("%d\n",prim()); }