P1340 兽径管理

最后一道生成树的绿题,那肯定是切了它呀

题意解释一下吧,就是每一次加入一条边,在加入之后是否能使这个图连通:可以连通,输出当前的最小路径之和;无法连通,输出-1

第一反应是裸的最小生成树,每次加一条边就直接跑一次最小生成树,判断是否连通就可以了,那么就诞生了第一份程序,我就不注释了,比较模板(同学的程序)

#include <bits/stdc++.h>
using namespace std;
struct node{
	int l , r , w;
};
node e[6010];
int n , m , now , tot , ans;
int fa[210];
int find(int x){
	if(fa[x] == x) return x;
	return fa[x] = find(fa[x]);
}
bool cmp(node x , node y){
	return x.w < y.w;
}
int main(){
	cin >> n >> m;
	while(m--){
		tot++;
		cin >> e[tot].l >> e[tot].r >> e[tot].w;
		for(int i = 1; i <= n; i++) fa[i] = i;
		sort(e + 1 , e + tot + 1 ,  cmp);
		now = 0 , ans = 0;
		for(int i = 1; i <= tot; i++){
			if(now == n - 1) break;
			int x = find(e[i].l) , y = find(e[i].r);
			if(x == y) continue;
			now++;
			ans += e[i].w;
			fa[x] = y;
		}
		if(now != n - 1) cout << -1 << endl;
		else cout << ans << endl;
	}
	return 0;
}

然后就发现T了很多点,只有50分,因为在每一次加入一条新边的时候,我们就需要重新一次快排,而这样的操作就会使时间复杂度相当大,那么我们就考虑如何换一种方法排序

插入排序,在每一次将边加入集合之前,我们先找出它应该在哪个位置,直接丢进去就好了,这个过程用数组处理会比较麻烦,但是利用STL中的vector的一些函数,就会使得整个程序简洁又方便理解

#include<bits/stdc++.h>
using namespace std;
int n,m;
struct node{
	int x,y,z;
};
vector<node>e;
int tot;
int f[5000005];
int find(int x){
	if(f[x]==x) return x;
	return f[x]=find(f[x]);
}
void merge(int x,int y){
	f[find(x)]=find(y);
}
int main(){
	scanf("%d%d",&n,&m);
	while(m--){
		int x,y,z;
		int k=0;
		scanf("%d%d%d",&x,&y,&z);
		tot++;
		for(register int i=0;i<tot-1;i++){
			if(z<e[i].z) break;
			k++;
		}//找到一个适合新边的位置 
		node bz;
		bz.x=x,bz.y=y,bz.z=z;
		e.insert(e.begin()+k,bz); //插入进去 
		if(tot<n-1) puts("-1");
		else{
			for(register int i=1;i<=n;i++) f[i]=i;
			int now=0,ans=0;
			for(register int i=1;i<=tot;i++){
				int fx=find(e[i-1].x),fy=find(e[i-1].y);
				if(fx!=fy){
					merge(fx,fy);
					ans+=e[i-1].z;
					now++;
				}
				if(now==n-1) break;
			}
			if(now==n-1) printf("%d\n",ans);
			else puts("-1");
		}
	}
	return 0;
}
posted @ 2020-07-23 20:25  Poetic_Rain  阅读(92)  评论(0编辑  收藏  举报