兽径管理
兽径管理
前言
第一次看这题的时候,被输出吓到了,有长有短(其实那些是注释...)
真正做这题是同桌喊我做的,其实这题很简单
算法
-
插入排序 & \(Kruskal\)求最小生成树
-
倒序\(Kruskal\)求最小生成树
会用两种方法讲解
插入排序
本种做法思路很简单:
-
不用转换问题,直接每次更新出一条边就将该条边存入可使用的边集
-
然后跑最小生成树,如果根本没有最小生成树,则是"-1",反之输出边权和
但是显然,时间复杂度会很高,因为每更新一条边就要对整个边集重新进行排序
那怎么优化一下?
用插入排序代替\(sort\)
因为本人太懒不想介绍插入排序,就直接引用一下别人的博客吧qwq
(建议使用\(vector\)实现插入排序),跑出来900+ms
倒序\(Kruskal\)
重点介绍这种做法
不得不说,倒序的思想在做题中十分重要!
因为很多按序开仓(或按序刷新)的题通过倒序思想一转换就很简单了
这题也是一样的:
我们将正序依次开放改为倒序关闭!
这样做的好处就是我们只需要排一次序,而不是每加入一条就刷新一次
感觉直到了倒序之后这题就好做了,直接给出代码,900+ms:
#include <bits/stdc++.h>
using namespace std;
int n,m,a,b,c,now,ans,fa[520010],sum[520010],flag[520010];
struct node {
int u,v,w,id;
} e[520010];
inline int find_fa(int x) {
if(x==fa[x]) return x;
return fa[x]=find_fa(fa[x]);
}
inline bool cmp(node x,node y) {
return x.w<y.w;
}
inline void kurskal() {
for(register int i=1;i<=n;i++) fa[i]=i;
now=0;ans=0;
for(register int i=1;i<=m;i++) {
if(flag[i]==1) continue;
int x=find_fa(e[i].u);
int y=find_fa(e[i].v);
if(x!=y) {
fa[x]=y;
now++;
ans+=e[i].w;
}
if(now==n-1) break;
}
}
int main() {
scanf("%d%d",&n,&m);
for(register int i=1;i<=m;i++) {
e[i].id=i;
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
sort(e+1,e+1+m,cmp);
for(register int i=m;i>=1;i--) {
kurskal();
if(now!=n-1) {
sum[i]=-1;
for(register int j=1;j<i;j++) sum[j]=-1;
break;
}
else sum[i]=ans;
for(register int j=1;j<=m;j++) {
if(e[j].id==i) flag[j]=1;
}
}
for(register int i=1;i<=m;i++) printf("%d\n",sum[i]);
return 0;
}
最后,如果有任何问题,欢迎留言区评论,我会及时回复、改正,谢谢orz
From:Eleven谦