题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=1601
题解:
是一道最小生成树的题目,先假象存在一个点n+1,这个点是(地下水),那么每个点要么向其他点连一条边,要么向地下水连一条边(即打井),那么他的目的就转成了要建一棵有n+1个树,要让树上的边权总和最小,那就是最小生成树咯。
代码:
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
int n,dp[305],w[305],p[305][305],fa[305];
struct node{
int x;int y;int d;
}edge[100005];
int cmp(node x,node y)
{
if (x.d!=y.d)
return x.d<y.d;
if (x.x!=y.x)
return x.x<y.x;
return x.y<y.y;
}
int find(int x)
{
if (fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
void unio(int x,int y)
{
fa[find(x)]=find(y);
}
int main()
{
scanf("%d",&n);
int tot=0;
for (int i=1;i<=n;i++)
{
fa[i]=i;
scanf("%d",&w[i]);
tot++;
edge[tot].x=n+1;
edge[tot].y=i;
edge[tot].d=w[i];
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
scanf("%d",&p[i][j]);
if (i!=j)
{
tot++;
edge[tot].x=i;
edge[tot].y=j;
edge[tot].d=p[i][j];
}
}
long long ans=0;
sort(edge+1,edge+1+tot,cmp);
for (int i=1;i<=tot;i++)
{
if (find(edge[i].x)!=find(edge[i].y))
{
ans+=edge[i].d;
unio(edge[i].x,edge[i].y);
}
}
printf("%lld",ans);
}