繁华的都市

这是一个**最小生成树(MST)**问题,要求:
1.连接所有节点(连通图)
2.边数最少 → 正好是 n−1 条(生成树)
3.在满足前两条下,最大边权最小 → 最小生成树中的最大边权
算法思路:
1.使用 Kruskal 或 Prim 求最小生成树。
2.Kruskal 按边权从小到大排序,用并查集维护连通性。
3.生成树中的最大边权就是答案。
注意:输出格式要求输出两个整数:选出的边数 和 最大边权。
1.边数一定是 n−1(因为保证连通)。
2.最大边权是生成树中最大的边权。
cs
#include <stdio.h>
#include <stdlib.h>
#define MAX_N 305
#define MAX_M 100005
typedef struct {
int u, v, w;
} Edge;
Edge edges[MAX_M];
int parent[MAX_N];
// 并查集:查找根
int find(int x) {
if (parent[x] != x)
parent[x] = find(parent[x]);
return parent[x];
}
// 并查集:合并
void union_set(int x, int y) {
int rx = find(x);
int ry = find(y);
if (rx != ry)
parent[rx] = ry;
}
// 比较函数,用于排序
int cmp(const void* a, const void* b) {
Edge* e1 = (Edge*)a;
Edge* e2 = (Edge*)b;
return e1->w - e2->w;
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
for (int i = 0; i < m; i++) {
scanf("%d %d %d", &edges[i].u, &edges[i].v, &edges[i].w);
}
// 按权值排序
qsort(edges, m, sizeof(Edge), cmp);
// 初始化并查集
for (int i = 1; i <= n; i++) {
parent[i] = i;
}
int edge_count = 0;
int max_weight = 0;
// Kruskal
for (int i = 0; i < m; i++) {
int u = edges[i].u;
int v = edges[i].v;
int w = edges[i].w;
if (find(u) != find(v)) {
union_set(u, v);
edge_count++;
if (w > max_weight)
max_weight = w;
}
if (edge_count == n - 1)
break;
}
printf("%d %d\n", edge_count, max_weight);
return 0;
}
城市规划大师

cs
#include <stdio.h>
#include <stdlib.h>
#define MAXN 1005
#define MAXM (MAXN * MAXN) // 完全图边数
typedef struct {
int u, v, w;
} Edge;
Edge edges[MAXM];
int parent[MAXN];
int ban[MAXN][MAXN]; // 禁止边标记
int n, k;
int x[MAXN], y[MAXN];
int edge_cnt = 0;
int abs(int a) { return a < 0 ? -a : a; }
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
// 曼哈顿距离
int manhattan(int i, int j) {
return abs(x[i] - x[j]) + abs(y[i] - y[j]);
}
int cmp(const void* a, const void* b) {
return ((Edge*)a)->w - ((Edge*)b)->w;
}
int find(int x) {
if (parent[x] != x)
parent[x] = find(parent[x]);
return parent[x];
}
void union_set(int x, int y) {
int rx = find(x);
int ry = find(y);
if (rx != ry)
parent[rx] = ry;
}
int main() {
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; i++) {
scanf("%d %d", &x[i], &y[i]);
}
// 初始化禁止边
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
ban[i][j] = 0;
for (int i = 0; i < k; i++) {
int u, v;
scanf("%d %d", &u, &v);
ban[u][v] = 1;
ban[v][u] = 1;
}
// 生成所有允许的边
edge_cnt = 0;
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
if (ban[i][j]) continue; // 禁止边跳过
edges[edge_cnt].u = i;
edges[edge_cnt].v = j;
edges[edge_cnt].w = manhattan(i, j);
edge_cnt++;
}
}
// Kruskal
qsort(edges, edge_cnt, sizeof(Edge), cmp);
for (int i = 1; i <= n; i++)
parent[i] = i;
int total = 0;
int cnt = 0;
for (int i = 0; i < edge_cnt; i++) {
int u = edges[i].u;
int v = edges[i].v;
int w = edges[i].w;
if (find(u) != find(v)) {
union_set(u, v);
total += w;
cnt++;
if (cnt == n - 1)
break;
}
}
printf("%d\n", total);
return 0;
}