DescriptionDescriptionDescription
有nnn块地,可以花费w[i]w[i]w[i]元在第iii块地上立井,也可以花费p[i][j]p[i][j]p[i][j]将iii地和jjj地联通
问最少花费多少钱才可以使得每块地都有水
InputInputInput
第一行,一个整数N
第2到N+1行,第i+1行输入W_i
第N+2到2N+1行,每行N个空格隔开的整数,表示P_ij
OutputOutputOutput
输出最少花费。
SampleSampleSample InputInputInput
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
SampleSampleSample OutputOutputOutput
9
HintHintHint
【样例解释】
FJ可以在草地4建井,并把草地2,3,4与草地1之间建立管道,花费为3+2+2+2=9
TrainTrainTrain ofofof ThoughtThoughtThought
可以建立一个点e,将e点和每一个点连接,其中的费用就是连接的点上立井的费用
然后跑一边遍primprimprim(最小生成树)就可以了
CodeCodeCode
#include<cstdio>
#include<cstring>
using namespace std;
bool b[305];
int ans,sum[305],p[305][305],w[305],n;
int main()
{
// freopen("water.in","r",stdin);
// freopen("water.out","w",stdout);
scanf("%d",&n);
for (int i=1; i<=n; ++i)
scanf("%d",&w[i]);
for (int i=1; i<=n; ++i)
for (int j=1; j<=n; ++j)
scanf("%d",&p[i][j]);
int e=n+1;
for (int i=1; i<=n; ++i)
p[e][i]=p[i][e]=w[i];//连边
memset(sum,0x7f,sizeof(sum));
sum[1]=0;
for (int i=1; i<=e; ++i)
{
int u=0;
for (int j=1; j<=e; ++j)
if (sum[j]<sum[u] && !b[j]) u=j;//找出最小的点
ans+=sum[u]; b[u]=true;
for (int j=1; j<=e; ++j)
if (u!=j && p[u][j]<sum[j]) sum[j]=p[u][j]; //更新数值
}
printf("%d",ans);
}