'commit'
This commit is contained in:
98
TangDou/CSP-J/AcWingTraining/T1/4089_Set.cpp
Normal file
98
TangDou/CSP-J/AcWingTraining/T1/4089_Set.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
const int N = 2e5 + 10; // 定义数组最大长度
|
||||
const int INF = 0x3f3f3f3f; // 定义一个很大的数作为哨兵
|
||||
int n; // 水果的总数
|
||||
set<int> apple, orange; // 使用两个集合分别存储苹果和橘子的位置
|
||||
|
||||
/*
|
||||
这个代码的主要思路是:
|
||||
|
||||
1. 使用set容器来存储水果的位置,而并不是记录的“块”,set的特点是自动排序且支持快速查找
|
||||
2. 每次都选择当前位置之后最近的目标水果(通过upper_bound实现)
|
||||
3. 每轮选择时会交替选择不同种类的水果
|
||||
4. 当一轮无法继续选择时(遇到INF),就开始新的一轮
|
||||
5. 有苹果有桔子,一替一个处理,在循环中不断变换需要找的水果类别,一个个输出;
|
||||
如果只有其中一种了,单独处理剩余的水果。
|
||||
|
||||
使用set的好处是:
|
||||
1. 自动维护水果位置的顺序
|
||||
2. upper_bound操作效率高,可以快速找到下一个合适的水果
|
||||
3. 删除操作也很高效
|
||||
4. 使用set要以避开区间合并的问题,代码更简单直接
|
||||
这种方法比暴力遍历数组的方法效率要高得多。
|
||||
*/
|
||||
|
||||
// 现在要挑选哪种
|
||||
int chooseFruit() {
|
||||
// 1 代表苹果,0 代表桔子
|
||||
int flag = 0;
|
||||
if (*apple.begin() < *orange.begin())
|
||||
flag = 1; // 如果苹果的最小位置更小,就先选苹果,
|
||||
// 否则先选橘子
|
||||
return flag;
|
||||
}
|
||||
|
||||
int main() {
|
||||
cin >> n;
|
||||
// 读入每个位置的水果类型并存入对应的集合
|
||||
for (int i = 1; i <= n; i++) {
|
||||
int x;
|
||||
cin >> x;
|
||||
if (x)
|
||||
apple.insert(i); // 1表示苹果,将位置i加入苹果集合
|
||||
else
|
||||
orange.insert(i); // 0表示橘子,将位置i加入橘子集合
|
||||
}
|
||||
|
||||
// 在两个集合末尾都插入一个无穷大的值作为哨兵
|
||||
// 这样可以防止upper_bound查找时越界
|
||||
apple.insert(INF);
|
||||
orange.insert(INF);
|
||||
|
||||
int cur = 0; // 记录当前处理到的位置
|
||||
bool flag = chooseFruit(); // 标记当前应该选择哪种水果:0表示苹果,1表示橘子
|
||||
// 通过比较两种水果的最小位置来决定先选择哪种
|
||||
// 如果苹果的最小位置更小,就先选苹果,否则先选橘子
|
||||
|
||||
// 主循环:只要还有水果可选就继续
|
||||
// apple.size() > 1 表示除了INF外还有苹果
|
||||
// orange.size() > 1 表示除了INF外还有橘子
|
||||
while ((flag && apple.size() > 1) || (!flag && orange.size() > 1)) {
|
||||
if (flag) { // 选择苹果的情况
|
||||
cur = *apple.upper_bound(cur); // 找到当前位置后面最近的苹果
|
||||
if (cur == INF) { // 如果找到的是INF,说明这一轮结束了
|
||||
cur = 0; // 重置当前位置为0, 重新决定下一轮先选哪种水果
|
||||
flag = chooseFruit(); // 下一轮是苹果还是桔子开始,需要根据函数决策
|
||||
puts(""); // 输出换行,表示一轮结束
|
||||
continue;
|
||||
}
|
||||
printf("%d ", cur); // 输出选中的苹果位置
|
||||
apple.erase(cur); // 从集合中删除已选择的苹果
|
||||
flag = !flag; // 切换到选择另一种水果
|
||||
} else { // 选择橘子的情况,逻辑同上
|
||||
cur = *orange.upper_bound(cur);
|
||||
if (cur == INF) {
|
||||
cur = 0;
|
||||
flag = chooseFruit();
|
||||
puts("");
|
||||
continue;
|
||||
}
|
||||
printf("%d ", cur);
|
||||
orange.erase(cur);
|
||||
flag = !flag;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理剩余的水果(如果有的话)
|
||||
puts(""); // 先输出一个换行
|
||||
while (apple.size() > 1) { // 处理剩余的苹果
|
||||
printf("%d\n", *apple.begin());
|
||||
apple.erase(apple.begin());
|
||||
}
|
||||
while (orange.size() > 1) { // 处理剩余的橘子
|
||||
printf("%d\n", *orange.begin());
|
||||
orange.erase(orange.begin());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user