最小生成樹【p2121】 拆地毯


題目描述--->p2121 拆地毯

分析

這題為什么是最大生成樹.

先來bb兩句

題目為拆地毯,讓我們剩下k個地毯.

題目想要我們求得最大的美麗度.

且要求我們

保留的地毯構成的圖中,任意可互相到達的兩點間只能有一種方式互相到達

很明顯,這一要求提示了我們最后結構會是一棵樹

(因為樹上路徑唯一啊,qwq.

然后根據正難則反的思想.

我們考慮拼地毯.

所以我們就想到了kruskal算法.(`・ω・´)

與普通kruskal不同的是,這里是一個最大生成樹

我們拼到k個得到的最大美麗度就是答案

為什么是拼到k個?

給大家一個圖.

如果此時題目要求我們剩下6個地毯,很明顯我們將6個地毯放入同一個並查集中就可滿足條件.

(已經預處理出較大美麗度的情況下)

拆地毯,讓我們剩下k個,因此我們合並出k個即可

所以就裸了

做法

我們只需要對最小生成樹略微修改,把邊權從大到小排序即可.

注意判斷已經加入到同一個並查集中的數量為k.

------------------代碼------------------

#include<bits/stdc++.h>
#define IL inline
#define RI register int
using namespace std;
IL void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s>'9' or s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s>='0' and s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int fa[100008],n,m,ans,cnt,k;
struct E{int pre,to,w;}edge[400008];
IL bool cmp(const E&a,const E&b)
{
    return a.w>b.w;
}//邊權從大到小排序.
IL int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}//路徑壓縮並查集
IL void kruskal()
{
    sort(edge+1,edge+m+1,cmp);//排序
    for(RI i=1;i<=m;i++)
    {
        RI u=edge[i].pre,v=edge[i].to,w=edge[i].w;
        int fu=find(u),fv=find(v);
        if(fu==fv) continue;
        ans+=w;fa[fv]=fu;
        cnt++;
        if(cnt==k) break;//判斷已經拼了k個地毯.
    }
}
int main(){
    in(n),in(m);in(k);
    for(RI i=1;i<=n;i++) fa[i]=i;//並查集初始化.
    for(RI i=1;i<=m;i++) 
    in(edge[i].pre),in(edge[i].to),in(edge[i].w);
    kruskal();//kruskal操作
    printf("%d",ans);
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com