【BZOJ】1601: [Usaco2008 Oct]灌水

时间:2023-03-09 01:29:41
【BZOJ】1601: [Usaco2008 Oct]灌水

【算法】最小生成树

【题解】

想到网络流,但是好像不能处理流量和费用的关系。

想到最短路,但好像不能处理重复选边的问题。

每条边只需要选一次,每个点就要遍历到,可以想到最小生成树。

建超级源向每个点连边,点与点连边,对n+1个点求最小生成树(MST)即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=;
int n,first[maxn],tot,fa[maxn];
struct edge{int u,v,w,from;}e[maxn*maxn*];
void insert(int u,int v,int w)
{tot++;e[tot].u=u;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;}
int getfa(int x){return fa[x]==x?x:(fa[x]=getfa(fa[x]));}
bool cmp(edge a,edge b)
{return a.w<b.w;}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
int u;
scanf("%d",&u);
insert(,i,u);
}
for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
{
int u;
scanf("%d",&u);
insert(i,j,u);
}
}
for(int i=;i<=n;i++)fa[i]=i;
sort(e+,e+tot+,cmp);
int cnt=,ans=;
for(int i=;i<=tot;i++)
if(getfa(e[i].u)!=getfa(e[i].v))
{
cnt++;fa[fa[e[i].u]]=fa[e[i].v];
ans+=e[i].w;
if(cnt>=n)break;
}
printf("%d",ans);
return ;
}