P2916 [USACO08NOV]安慰奶牛Cheering up the Cow

往奶牛里打气

题目评级不难。

感觉思路有值得借鉴的地方。(虽然少,毕竟积沙成塔吗qwq)

很容易看出来,是要求最小生成树的。

然后生成树的计算方式不一样。

我们考虑拼接(感觉大部分oi都可以使用类似的方法,即是先假设一部分已知,求另一部分)

我们已经知道了一颗不全的生成树,现在在往里添加点。

很显然,多出来的部分就是所添加的两点的点权加上二倍的边权(就是走两次)。

然后根绝上面。就可以写出算法。

不过开始点要多算一次。这个东西特判就好了。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using std::sort;
using std::min;
const int maxn=101000;
int val[maxn];
struct node
{
    int p1,p2;
    int val;
    void full(int a=0,int b=0,int c=0) { p1=a;p2=b;val=c; }
    bool operator <(const node &a)const
    {
        return val<a.val;
    }
};
node line[maxn];
int f[maxn];
int find(int x)
{
    return f[x]=(f[x]==x?x:find(f[x]));
}
int main()
{
    int n,p,pas=0x7fffffff;;
    scanf("%d%d",&n,&p);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&val[i]);
        f[i]=i;
        pas=min(pas,val[i]);
    }
    int a,b,c;
    for(int i=1;i<=p;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        line[i].full(a,b,val[a]+val[b]+c*2);
    }
    sort(line+1,line+1+p);
    int get=0,tot=0,i=0;
    while(get<n-1)
    {
        i++;
        int F1=find(line[i].p1),F2=find(line[i].p2);
        if(F1==F2)  continue;
        tot+=line[i].val;
        get++;
        f[F1]=F2;
    }
    printf("%d",tot+pas);
    return 0;
}

posted @ 2018-11-02 17:00  Lance1ot  阅读(121)  评论(0编辑  收藏  举报