来源:Luogu P1550,JZOJ #327
题目描述
希望把水源引入他的 个牧场,牧场的编号是 .他将水源引入某个牧场的方法有两个,一个是在牧场中打一口井,另一个是将这个牧场与另一个已经有水源的牧场用一根管道相连.
在牧场i中打井的费用是 .
把牧场i和j用一根管道相连的费用是 . 请你求出 最少要花多少钱才能够让他的所有牧场都有水源.
解题思路
- 建一个超级源点 ,和其他 个牧场连边,权值就是这个牧场打井的花费
- 数组初值为每个牧场打井的花费,直接 即可
代码君
#include <bits/stdc++.h>
using namespace std;
const int maxn=300+10;
int n,t=0;
int dis[maxn],vis[maxn*2],a[maxn][maxn];
inline int read() //快读
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void Freopen()
{
freopen("water..in","r",stdin);
freopen("water..out","w",stdout);
}
void init()
{
n=read();
memset(a,127,sizeof(a)); //初值
for (int i=1;i<=n;i++)
{
int x=read();
a[n+1][i]=x; //打井花费
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
int x=read();
a[i][j]=x; //i点到j点的花费为x
}
}
void prim(int st)
{
memset(dis,127,sizeof(dis));
memset(vis,0,sizeof(vis));
for (int i=1;i<=n+1;i++) dis[i]=a[n+1][i];
vis[st]=0; long long ans=0;
for (int i=1;i<=n;i++)
{
int Min=0x7777777f,mini=0;
for (int j=1;j<=n;j++)
if (!vis[j] && dis[j]<Min) Min=dis[j],mini=j; //找到当前距离最近的点
vis[mini]=1; //标记
if (Min!=0x7777777f) ans+=Min; //ans累加
for (int j=1;j<=n;j++)
{
if (!vis[j] && a[mini][j]<dis[j]) //dis迭代
{
dis[j]=a[mini][j];
}
}
}
printf("%d",ans);
}
int main()
{
Freopen();
init();
prim(1);
return 0;
}