题目大意:要给n块地灌水,对于每一块地,可以选择从另一块地引水过来,也可以选择建造水库,引水和建造水库都需要费用,问给N块地灌水的最小费用。
最终状态是个森林,对于每一棵树,都有一个点建造了水库,我们人工加入一个点,把建造了水库看做是连了这个点,最终状态就成了一棵树,这题也就转化为了最小生成树。
#include <cstdio>
#include <cstring>
using namespace std;
#define C (c=getchar())
inline void read(int &a)
{
a=0;static char c;
int f=1;
while(C<'0'||c>'9')
c=='-'?f=-1:0;
while(c>='0'&&c<='9')
a=a*10+c-'0',C;
return ;
}
int n,map[302][302],ans,f[302],dis[302],mn,p;
int main(void)
{
register int i,j,x;
read(n),++n;
for (i=1;i<n;++i)
read(x),map[i][n]=map[n][i]=x;
for (i=1;i<n;++i)
for (j=1;j<n;++j)
read(map[i][j]);
memset(dis,0x7f,sizeof(dis));
dis[1]=0;
for (i=1;i<=n;++i)
{
mn=2e9;
for (j=1;j<=n;++j)
if(dis[j]<mn&&f[j]==0)
mn=dis[j],p=j;
ans+=mn;
f[p]=1;
for (j=1;j<=n;++j)
if(f[j]==0&&dis[j]>map[p][j])
dis[j]=map[p][j];
}
printf("%d",ans);
return 0;
}