[USACO08OCT]Watering Hole

[USACO08OCT]Watering Hole

题目大意:

Farmer John 有\(n(n\le300)\)个牧场,他希望灌溉他的所有牧场。牧场编号为\(1\sim n\),要灌溉一个牧场有两种方式,一个是直接在这个牧场建设一个小型水库,另一个是从别的牧场向这个牧场引水。在第\(i\)个牧场建立小型水库需要\(W_i\)美元,而从第\(i\)个牧场向第\(j\)个牧场引水需要\(P_{i,j}\)美元。即便牧场\(j\)没有建设小型水库,只要有别的有水的水库向它引水,那它自己也有水,而且可以向别的水库引水。请告诉 FJ 灌溉所有牧场所需的最小代价。

思路:

\(P_i\)相当于连向虚点\(0\)的边,然后直接Kruskal即可。

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
const int N=301,M=45150;
struct Edge {
    int u,v,w;
    bool operator < (const Edge &rhs) const {
        return w<rhs.w;
    }
};
Edge e[M];
int m;
class DisjointSet {
    private:
        int anc[N];
        int find(const int &x) {
            return x==anc[x]?x:anc[x]=find(anc[x]);
        }
    public:
        void reset(const int &n) {
            for(register int i=0;i<=n;i++) anc[i]=i;
        }
        void merge(const int &x,const int &y) {
            anc[find(x)]=find(y);
        }
        bool same(const int &x,const int &y) {
            return find(x)==find(y);
        }
};
DisjointSet s;
int main() {
    const int n=getint();
    for(register int i=1;i<=n;i++) {
        e[m++]=(Edge){0,i,getint()};
    }
    for(register int i=1;i<=n;i++) {
        for(register int j=1;j<=n;j++) {
            const int w=getint();
            if(j<i) e[m++]=(Edge){i,j,w};
        }
    }
    s.reset(n);
    std::sort(&e[0],&e[m]);
    int ans=0;
    for(register int i=0;i<m;i++) {
        const int &u=e[i].u,&v=e[i].v,&w=e[i].w;
        if(s.same(u,v)) continue;
        s.merge(u,v);
        ans+=w;
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/skylee03/p/9630252.html