刷题笔记
1. 万能头文件:
#include <bits/stdc++.h>
2. 初始化生成连续整数:0、1、2、...、N
iota(fa, fa + n + 1, 0); // 容器的起始迭代器、容器的结束迭代器以及要填充的初始值。
3. 小于号重载:按cost从大到小排序
struct Edge {
int a, b, cost;
bool operator< (const Edge &b) {
return this->cost < b.cost;
}
};
vector<Edge> repair;
sort(repair.begin(), repair.end());
4. 匿名函数
struct Edge {
int a, b, cost;
};
vector<Edge> repair;
sort(repair.begin(), repair.end(), [](const Edge &a, const Edge &b) {
return a.cost < b.cost;
});
5. 并查集模板
struct UnionSet {
int *fa, n;
UnionSet(int n) : n(n) {
fa = new int[n + 1];
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
}
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]); // 路径压缩
}
void merge(int a, int b) {
int ra = find(a), rb = find(b);
if (ra == rb) return ;
fa[ra] = rb;
return ;
}
int count() { // 统计类的个数
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (fa[i] == i) cnt++;
}
return cnt;
}
};
题解代码
/*************************************************************************
> File Name: 1001.cpp
> Author: jby
> Mail:
> Created Time: Tue 22 Aug 2023 10:00:25 PM CST
************************************************************************/
// 这是一个图问题、连通问题。
// 用到了最小生成树的思想。
#include<bits/stdc++.h>
using namespace std;
struct UnionSet {
int *fa, n;
UnionSet(int n) : n(n) {
fa = new int[n + 1];
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
}
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void merge(int a, int b) {
int ra = find(a), rb = find(b);
if (ra == rb) return ;
fa[ra] = rb;
return ;
}
int count() {
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (fa[i] == i) cnt++;
}
return cnt;
}
};
struct Edge {
int a, b, cost;
bool operator< (const Edge &b) {
return this->cost < b.cost;
}
};
int n, m, max_cost; // n 城市数量, m 铁路数量, max_cost最大代价
vector<int> max_city; // 最终结果有哪些城市需要保护
int costs[505];
vector<Edge> repair, use;
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++) {
int a, b, c, d;
scanf("%d%d%d%d", &a, &b, &c, &d);
if (d == 0) repair.push_back(Edge{a, b, c});
else use.push_back(Edge{a, b, c});
}
sort(repair.begin(), repair.end());
for (int i = 1; i <= n; i++) {
UnionSet u(n);
for (auto x : use) {
int fa = u.find(x.a), fb = u.find(x.b);
if (x.a != i && x.b != i && fa != fb) {
u.merge(x.a, x.b);
}
}
for (auto x : repair) {
int fa = u.find(x.a), fb = u.find(x.b);
if (x.a != i && x.b != i && fa != fb) {
u.merge(x.a, x.b);
costs[i] += x.cost;
}
}
if (u.count() > 2) costs[i] = INT_MAX; // 说明当前城市被攻占了,其余城市不可能连通,最重要。
}
for (int i = 1; i <= n; i++) {
if (costs[i] > max_cost) {
max_city.clear();
max_cost = costs[i];
max_city.push_back(i);
} else if (costs[i] > 0 && costs[i] == max_cost) {
max_city.push_back(i);
}
}
if (max_city.size() == 0) {
printf("%d\n", 0);
} else {
sort(max_city.begin(), max_city.end());
for (int i = 0; i < max_city.size(); i++) {
i && printf(" ");
printf("%d", max_city[i]);
}
printf("\n");
}
return 0;
}
下面这版代码,我把并查集拆掉了,并取消了重载小于号,转而用上了匿名函数。
// 这是一个图问题、连通问题。
// 用到了最小生成树的思想。
#include<bits/stdc++.h>
using namespace std;
struct Edge {
int a, b, cost;
// 可以用重载小于号,也可以在sort方法中用匿名函数,本质都是一样的。
// bool operator< (const Edge &b) {
// return this->cost < b.cost;
// }
};
int n, m, max_cost; // n 城市数量, m 铁路数量, max_cost最大代价
vector<int> max_city; // 最终结果有哪些城市需要保护
int costs[505], fa[505]; // 记录每个城市对应的代价
vector<Edge> repair, use;
int count() {
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (fa[i] == i) cnt++;
}
return cnt;
}
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]); // 没必要为了统计类个数而牺牲路径优化。
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++) {
int a, b, c, d;
scanf("%d%d%d%d", &a, &b, &c, &d);
if (d == 0) {
repair.push_back(Edge{a, b, c});
} else {
use.push_back(Edge{a, b, c});
}
}
sort(repair.begin(), repair.end(), [](const Edge &a, const Edge &b) {
return a.cost < b.cost;
});
for (int i = 1; i <= n; i++) {
iota(fa, fa + n + 1, 0); // 初始化并查集
for (auto x : use) {
int ra = find(x.a), rb = find(x.b);
if (x.a != i && x.b != i && ra != rb) {
fa[ra] = rb;
}
}
for (auto x : repair) {
int ra = find(x.a), rb = find(x.b);
if (x.a != i && x.b != i && ra != rb) {
fa[ra] = rb;
costs[i] += x.cost;
}
}
if (count() > 2) {
costs[i] = INT_MAX;
}
}
for (int i = 1; i <= n; i++) {
if (costs[i] > max_cost) {
max_cost = costs[i];
max_city.clear();
max_city.push_back(i);
} else if (costs[i] > 0 && costs[i] == max_cost) {
max_city.push_back(i);
}
}
if (max_city.empty()) {
printf("0\n");
} else {
for (int i = 0; i < max_city.size(); i++) {
i && printf(" ");
printf("%d", max_city[i]);
}
printf("\n");
}
return 0;
}