題目描述--->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);
}
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。