洛谷P1550 [USACO08OCT]Watering Hole G
1、简明题意
要引水入 \(n\)个牧场,一开始每个牧场没水,可以挖井或铺管道,第 \(i\)个牧场挖井要 \(w[i]\)块钱,铺连接第 \(i\), \(j\)两个牧场的管道要 \(p[i][j]\)块钱,且 \(p[i][j]=p[j][i]\)。求把\(n\)个牧场全部变成有水的最小代价。
2、思路:
一开始还真的没思路TAT
最后经过多方询问,终于明白了这题怎么写。
先假设还有第 \(n+1\)个牧场,这个牧场很奇怪,自己就有水(水从天而降)。
那么从这个牧场到第 \(i\)个牧场的距离便为 \(w[i]\)。
最后跑一遍 \(n+1\)个点的最小生成树就行了。
就是最小生成树模板。
3、code:
kruscal版:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
const int N=305;
const int M=100005;
int ans=0;
struct node{
int u,v,w;
}a[M];
int fa[N],n,ww[N],mapp[N][N];
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
x=find(x);
y=find(y);
if(x!=y)
{
fa[y]=x;
}
}
bool cmp(node x,node y)
{
return x.w<y.w;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
fa[i]=i;
}
int cnt=0;
for(int i=1;i<=n;i++)
{
cin>>ww[i];
a[++cnt].u=i,a[cnt].v=n+1,a[cnt].w=ww[i];
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>mapp[i][j];
if(i>j)
{
a[++cnt].u=i;
a[cnt].v=j;
a[cnt].w=mapp[i][j];
}
}
}
sort(a+1,a+cnt+1,cmp);
for(int i=1;i<=cnt;i++)
{
if(find(a[i].u)!=find(a[i].v))
{
merge(a[i].u,a[i].v);
ans+=a[i].w;
}
}
cout<<ans;
return 0;
}