社区讨论

请问为什么一定是s-1条边用卫星电话通讯

P1991无线通讯网参与者 4已保存回复 4

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
4 条
当前快照
1 份
快照标识符
@luza20q5
此快照首次捕获于
2024/04/14 16:42
2 年前
此快照最后确认于
2024/04/14 19:49
2 年前
查看原帖
一开始我用一个很复杂的思路写了个kruscal 然后只得了60分 (可能有点复杂……)
CPP
#include <cmath>
#include <queue>
#include <vector>
#include <bitset>
#include <climits>
#include <iomanip>
#include <iostream>
#include <algorithm>

#define debug(x) (cerr << x << '\n')

using namespace std;

const int N = 505;

int s, p;
double ans = 0.0;
vector<int> fa(N);
bitset<N> hasPhone;	/* 判断哨所是否有卫星电话 */

struct Node {
	double x;
	double y;
};
vector<Node> a;

struct Edge {
	int from;
	int to;
	double w;
	bool operator < (const Edge& a) const {
		return w < a.w;
	}
};
vector<Edge> edge;

inline void init() {
	for (int i = 0; i < N; i++) {
		fa[i] = i;
	}
}

inline double dis(const int& i1, const int& i2) {
	/* 哨所距离 */ 
	return sqrt(pow(abs(a[i1].x - a[i2].x), 2) +	\
	pow(abs(a[i1].y - a[i2].y), 2));
}

inline int find(const int& u) {
	return fa[u] == u ? u : fa[u] = find(fa[u]);
}

void kruscal() {
	priority_queue<Edge> pq; /* 存用过的最大的边 */
	sort(edge.begin(), edge.end());
	/* for循环结束后ans为最长边 */
	for (auto x : edge) {
		if (find(x.from) == find(x.to)) {
			continue;
		}
		fa[find(x.from)] = find(x.to);
		ans = x.w;
		pq.push(x);
	}
//	for (int i = 1; i <= s - 1; i++) {
	while (s > 0) {
		/* 目前边权最大的边 */
		Edge x = pq.top();
		pq.pop();
		/* 如果起点没有卫星电话 */
		if (!hasPhone[x.from]) {
			/* 判断剩的卫星电话够不够用 */
			if (s < 1) {
				break;
			} else {
				/* 给起点安装卫星电话 */ 
				s--;
				hasPhone[x.from] = true;
			}
		}
		/* 如果终点没有卫星电话 */
		if (!hasPhone[x.to]) {
			/* 判断剩的卫星电话够不够用 */
			if (s < 1) {
				break;
			} else {
				/* 给终点安装卫星电话 */ 
				s--;
				hasPhone[x.to] = true;
			}
		}
		/* 如果ans是当前处理的值 */
		if (ans == x.w) {
			/* x.w使用卫星电话,代价是0,ans取比x.w小的	\
			里面最大的 */
			ans = pq.top().w;
		}
//		pq.pop();
//		ans = pq.top().w;
	}
}

int main() {
	/* 初始化并查集 */ 
	init();
	/* 输入 */
	cin >> s >> p;
	double x, y;
	a.push_back({ 0, 0 });
	for (int i = 1; i <= p; i++) {
		cin >> x >> y;
		a.push_back({ x, y });
	}
	/* 建边(每两个节点都要建) */
	for (int i = 1; i <= p; i++) {
		for (int j = i + 1; j <= p; j++) {
			if (i == j) {
				continue;
			}
			edge.push_back({ i, j, dis(i, j) });
		}
	}
	/* 计算最小生成树 */
	kruscal();
	/* 输出答案(保留2位小数) */
	cout << fixed << setprecision(2) << ans;
	return 0;
}
后来在同学的见一下,将一大堆复杂的逻辑改成删s-1条边,就A了
CPP
#include <cmath>
#include <queue>
#include <vector>
#include <bitset>
#include <climits>
#include <iomanip>
#include <iostream>
#include <algorithm>

#define debug(x) (cerr << x << '\n')

using namespace std;

const int N = 505;

int s, p;
double ans = 0.0;
vector<int> fa(N);
bitset<N> hasPhone;	/* 判断哨所是否有卫星电话 */

struct Node {
	double x;
	double y;
};
vector<Node> a;

struct Edge {
	int from;
	int to;
	double w;
	bool operator < (const Edge& a) const {
		return w < a.w;
	}
};
vector<Edge> edge;

inline void init() {
	for (int i = 0; i < N; i++) {
		fa[i] = i;
	}
}

inline double dis(const int& i1, const int& i2) {
	/* 哨所距离 */ 
	return sqrt(pow(abs(a[i1].x - a[i2].x), 2) +	\
	pow(abs(a[i1].y - a[i2].y), 2));
}

inline int find(const int& u) {
	return fa[u] == u ? u : fa[u] = find(fa[u]);
}

void kruscal() {
	priority_queue<Edge> pq; /* 存用过的最大的边 */
	sort(edge.begin(), edge.end());
	/* for循环结束后ans为最长边 */
	for (auto x : edge) {
		if (find(x.from) == find(x.to)) {
			continue;
		}
		fa[find(x.from)] = find(x.to);
		ans = x.w;
		pq.push(x);
	}
	for (int i = 1; i <= s - 1; i++) {
//	while (s > 0) {
//		/* 目前边权最大的边 */
//		Edge x = pq.top();
//		pq.pop();
//		/* 如果起点没有卫星电话 */
//		if (!hasPhone[x.from]) {
//			/* 判断剩的卫星电话够不够用 */
//			if (s < 1) {
//				break;
//			} else {
//				/* 给起点安装卫星电话 */ 
//				s--;
//				hasPhone[x.from] = true;
//			}
//		}
//		/* 如果终点没有卫星电话 */
//		if (!hasPhone[x.to]) {
//			/* 判断剩的卫星电话够不够用 */
//			if (s < 1) {
//				break;
//			} else {
//				/* 给终点安装卫星电话 */ 
//				s--;
//				hasPhone[x.to] = true;
//			}
//		}
//		/* 如果ans是当前处理的值 */
//		if (ans == x.w) {
//			/* x.w使用卫星电话,代价是0,ans取比x.w小的	\
//			里面最大的 */
//			ans = pq.top().w;
//		}
		pq.pop();
		ans = pq.top().w;
	}
}

int main() {
	/* 初始化并查集 */ 
	init();
	/* 输入 */
	cin >> s >> p;
	double x, y;
	a.push_back({ 0, 0 });
	for (int i = 1; i <= p; i++) {
		cin >> x >> y;
		a.push_back({ x, y });
	}
	/* 建边(每两个节点都要建) */
	for (int i = 1; i <= p; i++) {
		for (int j = i + 1; j <= p; j++) {
			if (i == j) {
				continue;
			}
			edge.push_back({ i, j, dis(i, j) });
		}
	}
	/* 计算最小生成树 */
	kruscal();
	/* 输出答案(保留2位小数) */
	cout << fixed << setprecision(2) << ans;
	return 0;
}
请问为什么一定删s - 1条边 谢谢

回复

4 条回复,欢迎继续交流。

正在加载回复...