蒟蒻复习之-----最小生成树

14 篇文章 0 订阅

#蒟蒻复习之-----最小生成树#


//又一基础算法被深究QAQ

一般有两种方法,但考虑到博主只会kruskal,就不说Prim了

##kruskal##
kruskal是基于贪心的,对所有边sort,再从小加边
模板.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn = 200000 + 100;
int n,m,f[maxn],tot,sum;
struct edge {
	int u,v,w;
}e[maxn];

int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') {
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}

bool cmp(edge a,edge b) {
	return a.w < b.w;
}

int find(int x) {
    if(f[x] == x) return f[x];
    f[x] = find(f[x]);
    return f[x];
}

int main() {
	n = read(), m = read();
	for(int i = 1; i <= m; i++) {
		e[i].u = read(), e[i].v = read(), e[i].w = read();
	}
	for(int i = 1; i <= n; i++) f[i] = i;
	sort(e+1,e+1+m,cmp);
	for(int i = 1; i <= m; i++) {
		int t1 = find(e[i].u), t2 = find(e[i].v);
		if(t1 != t2) {
			f[t1] = t2;
			tot++;
			sum += e[i].w;
		} 
		if(tot == n-1)	break;
	}
	cout<<sum<<endl;
	return 0;
}

#次小生成树#

首先先要知道什么是最小瓶颈路
在无向图中求一条连接两点的路径, 使路径上权值最大的边尽可能的小, 则这条路径称为最小瓶颈路。
其实就是最小生成树

所以可以想到一种简单的方法,就是举要添加哪一条边, 加上这条边的权值, 然后将这条边连接的两点的最小瓶颈路上的最大边权减去, 就得到了一棵新的生成树。 复杂度O(n²+mlogm)

[vijos1070]新年趣事之游戏

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn = 200000 + 100;
int n,m,f[maxn],tot,sum,vis[maxn];
struct node {
	int u,v,w;
}no[maxn];
struct edge{
	int u,v,w,next;
}e[maxn];
int head[maxn],cnt = 0;

void add(int u, int v, int w) {
	e[++cnt] = (edge){u,v,w,head[u]};
	head[u] = cnt;
}

int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') {
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}

bool cmp(node a,node b) {
	return a.w < b.w;
}

int find(int x) {
    if(f[x] == x) return f[x];
    f[x] = find(f[x]);
    return f[x];
}


void kruskal() {
	for(int i = 1; i <= n; i++) f[i] = i;
	sort(no+1,no+1+m,cmp);
	for(int i = 1; i <= m; i++) {
		int t1 = find(no[i].u), t2 = find(no[i].v);
		if(t1 != t2) {
			f[t1] = t2;
			tot++;
			sum += no[i].w;
			vis[i] = 1;
			add(no[i].u,no[i].v,no[i].w);
			add(no[i].v,no[i].u,no[i].w);
		} 
		if(tot == n-1)	break;
	}
}
int now,d[600][600];
void dfs(int x, int fa, int num) {
	d[now][x] = num;
	for(int i = head[x]; i; i = e[i].next) {
		int v = e[i].v;
		if(v != fa) {
			dfs(v,x,max(num,e[i].w));
		}
	}
}

void work() {
	n = read(), m = read();
	for(int i = 1; i <= m; i++) {
		no[i].u = read(), no[i].v = read(), no[i].w = read();
	}
	kruskal();
	cout<<"Cost: ";
	if(tot != n-1) cout<<"-1"<<endl;
		else cout<<sum<<endl;
	for(int i = 1; i <= n; i++) {
		now = i;
		dfs(i,0,0);
	}
	int ans = 1<<29;
	for(int i = 1;i <= m; i++) {
		if(!vis[i]) ans = min(ans,sum + no[i].w - d[no[i].u][no[i].v]);
	}
	cout<<"Cost: ";
	if(ans == 1<<29) cout<<"-1"<<endl;
		else cout<<ans<<endl;
}

int main() {
	work();
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值