UVA 10600 ACM Contest and Blackout(次小生成树)

题目传送

次小生成树模板题:
先求出最小生成树,然后再遍历所有没用过的边,加上去,这时会形成一个环,去掉环中的第二大的边,更新结果。

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 110;
const int maxm = maxn * maxn;

int n, m;
int par[maxn];
int maxd[maxn][maxn];
int used[maxm];
vector<int> G[maxn];

struct edgs {
	int from, to, dis;
	bool operator < (const edgs& a) const {
		return dis < a.dis;
	}
}edg[maxm];

void init() //初始化
{
	for (int i = 1; i <= n; i++) {
		par[i] = i;
		G[i].clear();
		G[i].push_back(i); //卡了好久,很关键的一步
		for (int j = 1; j <= n; j++) maxd[i][j] = 0;	
	}
	memset(used, 0, sizeof(used));
}

int find(int x)
{
	return par[x] == x ? x : par[x] = find(par[x]);
}

int main(void)
{
	int t;
	cin >> t;
	while (t--) {
		cin >> n >> m;
		init();
		for (int i = 1; i <= m; i++) {
			int a, b, c;
			cin >> a >> b >> c;
			edg[i].from = a;
			edg[i].to = b;
			edg[i].dis = c;
		}
		sort(edg + 1, edg + m + 1);
		int ans = 0, cnt = 0;
		for (int i = 1; i <= m; i++) {
			int rf = find(edg[i].from);
			int rt = find(edg[i].to);
			if (rf == rt) continue;
			ans += edg[i].dis;
			used[i] = 1;
			for (int j = 0; j < G[rf].size(); j++) {
				for (int l = 0; l < G[rt].size(); l++) { //记录两点间的最长边
					maxd[G[rf][j]][G[rt][l]] = maxd[G[rt][l]][G[rf][j]] = edg[i].dis;
				}
			}
			par[rf] = rt;
			for (int j = 0; j < G[rf].size(); j++) G[rt].push_back(G[rf][j]); //合并两个连通块
			if (++cnt == n - 1) break;
		}
		cout << ans << " ";
		int res = 0x3f3f3f3f;
		for (int i = 1; i <= m; i++) {
			if (!used[i]) {
				res = min(res, ans + edg[i].dis - maxd[edg[i].from][edg[i].to]); //更新结果
			} 
		}
		cout << res << endl;
	}
	return 0;
}
发布了30 篇原创文章 · 获赞 50 · 访问量 5295

猜你喜欢

转载自blog.csdn.net/qq_43054573/article/details/104437431