【BZOJ】1601: [Usaco2008 Oct]灌水

【算法】最小生成树

【题解】

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

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

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

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

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=310;
int n,first[maxn],tot,fa[maxn];
struct edge{int u,v,w,from;}e[maxn*maxn*3];
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=1;i<=n;i++)
    {
        int u;
        scanf("%d",&u);
        insert(0,i,u);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            int u;
            scanf("%d",&u);
            insert(i,j,u);
        }
    }
    for(int i=1;i<=n;i++)fa[i]=i;
    sort(e+1,e+tot+1,cmp);
    int cnt=0,ans=0;
    for(int i=1;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 0;
}
View Code
原文地址:https://www.cnblogs.com/onioncyc/p/7197862.html