Luogu P1550 [USACO08OCT]打井-Watering Hole (图论-Prim)

来源:Luogu P1550,JZOJ #327

题目描述

F a r m e r J o h n Farmer John 希望把水源引入他的 N ( 1 < = N < = 300 ) N (1 <= N <= 300) 个牧场,牧场的编号是 1   N 1~N .他将水源引入某个牧场的方法有两个,一个是在牧场中打一口井,另一个是将这个牧场与另一个已经有水源的牧场用一根管道相连.

在牧场i中打井的费用是 W i ( 1 < = W i < = 100000 ) W_i (1 <= W_i <= 100000) .

把牧场i和j用一根管道相连的费用是 P i j ( 1 < = P i j < = 100000 , P i j = P j i , P i i = 0 ) P_ij (1 <= P_ij <= 100000, P_ij = P_ji, P_ii = 0) . 请你求出 F a r m e r J o h n Farmer John 最少要花多少钱才能够让他的所有牧场都有水源.

解题思路

  • 建一个超级源点 n + 1 n+1 ,和其他 n n 个牧场连边,权值就是这个牧场打井的花费
  • d i s dis 数组初值为每个牧场打井的花费,直接 P r i m Prim 即可

代码君

#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;
}
发布了27 篇原创文章 · 获赞 33 · 访问量 1685

猜你喜欢

转载自blog.csdn.net/qq_43081996/article/details/104170354