刚接触PAT顶级的题目,感觉困难的点在于,对题目能够有一个准确的把握没那么容易。到底用哪种算法思想也需要花很多时间甄别。
再者就是锻炼编码能力,后期的优化真的很重要,在比较不同的实现方式的优劣的过程中,精简我们的代码。
关于引入这个头文件,有时候会报错是以下原因:
这是因为你使用了`#include
如果你想使用标准库的话,你可以直接包含相应的头文件,比如`#include
另外,使用`#include
这段代码使用了C++标准库中的`iota`函数,它的作用是将一个指定范围内的值依次填充到一个容器中。
具体来说,`iota`函数接受三个参数:容器的起始迭代器、容器的结束迭代器以及要填充的初始值。
在这段代码中,`iota`函数被用于填充一个名为`father`的容器,容器的起始迭代器为`father`,结束迭代器为`father + N + 1`,初始值为0。
换句话说,这段代码将从`father`开始的`N+1`个元素依次填充为0、1、2、...、N。
struct Edge {
int a, b, cost;
bool operator< (const Edge &b) {
return this->cost < b.cost;
}
};
vector repair;
sort(repair.begin(), repair.end());
struct Edge {
int a, b, cost;
};
vector repair;
sort(repair.begin(), repair.end(), [](const Edge &a, const Edge &b) {
return a.cost < b.cost;
});
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
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 max_city; // 最终结果有哪些城市需要保护
int costs[505];
vector 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
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 max_city; // 最终结果有哪些城市需要保护
int costs[505], fa[505]; // 记录每个城市对应的代价
vector 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;
}