• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
北极通讯网络 Kruskal算法-扩展

北极通讯网络

题目

北极通讯网络

思路

​ 一开始想的时候,先删除最大的点,然后依次枚举,找到不满足题目条件,即卫星数目不够图连通,也就是连通块的数量大于卫星数,那么这个数的上一个边权,就是我们要找的最小的\(d\), 其实这个是满足单调性的可以进行二分。

​ 我们可以将题目抽象为:找到最小的\(d\), 满足删除所有大于\(d\)的边权后,连通块的数量不超过\(k\)。

​ 二分的话,复杂度在\(\Theta(MlogM)\), 貌似也可以, 但是我们用\(Kruskal\)算法的时候我们发现并不需要这个,我们可以优化成\(\Theta(M)\), 用\(Kruskal\)算法来从最小边权枚举,每次并查集操作时,我们将连通块的数量\(N\)减一, 维护连通快的数量,直到满足条件。

Code

#include <bits/stdc++.h>
#define ff first
#define ss second
using i64 = long long;

const int N = 600, M = 2e5 + 10;

int n, m, k;

int p[N];

struct Edge {
	int a, b;

	double w;

	bool operator<(const Edge &t) const {
		return  w < t.w;
	}	
}edge[M];

std::vector<std::pair<int, int>> v1;

double get_dist(int i, int j) {
	int dx = v1[i].ff - v1[j].ff;
	int dy = v1[i].ss - v1[j].ss;

	return sqrt(std::abs(dx * dx + dy * dy));
}

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

double kruskal() {
	int cnt = n;
	double res = 0;

	std::sort(edge + 1, edge + 1 + m);

	for (int i = 1; i <= m; i ++) {
		// std::cout << edge[i].w << "\n";
		int a = edge[i].a, b = edge[i].b;
		int fa = find(a), fb = find(b);

		double w = edge[i].w;

		if (fa != fb) {
			if (cnt <= k) {
				break;
			}
			p[fa] = fb;
			res = w;
			cnt --;
		}
	}

	return res;
}


int main() {
	std::cin >> n >> k;

	v1.resize(n + 1);

	for (int i = 1; i <= n; i ++) p[i] = i;

	for (int i = 1; i <= n; i ++) {
		std::cin >> v1[i].ff >> v1[i].ss;
	}

	for (int i = 1; i <= n; i ++) {
		for (int j = 1; j < i; j ++) {
			edge[++ m] = {i, j, get_dist(i, j)};
		}
	}

	printf("%.2lf", kruskal());
}
posted on 2023-05-06 21:06  Jack404  阅读(59)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3