luogu 1550 [Usaco2008 Oct]打井 最小生成树+小技巧

此题似乎显然最小生成树,小技巧需要注意:

在每个点出井水,需要花费,实际上可以把井水视作所有井下统一的一点,需要走路径到达此点,新图上再最小生成树

将点化作边处理

还有题目写的数据范围一般不可信,开大点总是好的,代码就不贴了吧

#include<bits/stdc++.h>
#define rep(i,x,y) for(register ll i=x;i<=y;i++)
#define ll long long
using namespace std;
const ll N=1000;
const ll M=100000;
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}
ll n,m,a[N],g[N][N],x,cnt,xx,yy,fa[N];ll ans;
inline ll find(ll x){return fa[x]==x?x:fa[x]=find(fa[x]);}
struct node{ll u,v,w;}e[M];
bool cmp(node a,node b){return a.w<b.w;}
int main(){
    n=read();cnt=n+1;
    rep(i,1,n) fa[i]=i,x=read(),e[++m]=(node){i,n+1,x};fa[n+1]=n+1;
    rep(i,1,n)rep(j,1,n) g[i][j]=read();
    rep(i,1,n)rep(j,i+1,n) e[++m]=(node){i,j,g[i][j]};
    sort(e+1,e+1+m,cmp);
    rep(i,1,m){
        xx=find(e[i].u),yy=find(e[i].v);
        if(xx!=yy) fa[xx]=yy,cnt--,ans+=e[i].w;
        if(cnt==1) break;
    }printf("%d\n",ans);return 0;
}

 

posted @ 2018-09-06 18:12  ASDIC减除  阅读(100)  评论(0编辑  收藏  举报