Description:
农民John 决定将水引入到他的n(1<=n<=300)个牧场。他准备通过挖若干井,并在各块田中修筑水道来连通各块田地以供水。在第i 号田中挖一口井需要花费W_i(1<=W_i<=100,000)元。连接i 号田与j 号田需要P_ij (1 <= P_ij <= 100,000 , P_ji=P_ij)元。请求出农民John 需要为使所有农场都与有水的农场相连或拥有水井所需要的钱数。
Analysis:
我们可以转换一下思路,把每个点的点权当成一个指向自己的边权,然后构造一棵最小生成树就好了!
Code
注意数组大小!
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define N 500
using namespace std;
struct edge{
int from,to,w;
bool operator < (const edge &a) const {
return w < a.w;
}
}e[100001];
int set[N],w[N],num_edge,n;
inline void add(int from,int to,int w)
{
e[++num_edge].from = from;
e[num_edge].to = to;
e[num_edge].w = w;
}
int findset(int x)
{
if(set[x] == x) return x;
return set[x] = findset(set[x]);
}
void unionset(int a,int b)
{
a = findset(a);
b = findset(b);
set[a] = b;
}
void solve()
{
sort(e + 1,e + 1 + num_edge);
int k = 0,ans = 0;
for(int i = 1;i <= num_edge;++i)
{
int a = e[i].from,b = e[i].to;
if(findset(a) != findset(b))
{
unionset(a,b);
++k;
ans += e[i].w;
}
if(k == n) break;
}
printf("%d
",ans);
}
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;++i)
{
scanf("%d",&w[i]);
set[i] = i;
add(0,i,w[i]);
}
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= n;++j)
{
int v;
scanf("%d",&v);
if(i > j)
{
add(i,j,v);
}
}
}
solve();
return 0;
}