mirror of
https://gitcode.com/Zengtudor/alg2025.git
synced 2025-10-26 10:02:47 +00:00
feat: 添加奶牛碰撞模拟算法实现
实现奶牛碰撞模拟算法,包括交叉点检测、排序处理和动态规划计算责备数。该算法通过几何条件筛选潜在碰撞点,按空间位置排序后模拟处理碰撞事件,使用动态规划高效计算每头奶牛的最终责备数。
This commit is contained in:
parent
88b33ff757
commit
779ef8b327
121
src/10/20/P7150.cpp
Normal file
121
src/10/20/P7150.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
// 为了提高IO效率,这是OI/ACM竞赛中的常用技巧
|
||||
#define FAST_IO std::ios_base::sync_with_stdio(false); std::cin.tie(NULL);
|
||||
|
||||
// 奶牛结构体,存储了所有必要信息
|
||||
struct Cow {
|
||||
int id; // 奶牛的原始输入编号 (0 to N-1)
|
||||
long long x, y; // 初始坐标
|
||||
char dir; // 方向 'N' 或 'E'
|
||||
};
|
||||
|
||||
// 交叉点/碰撞事件结构体
|
||||
struct Intersection {
|
||||
long long x, y; // 交叉点的坐标
|
||||
int north_cow_id; // 参与该交叉点的北向牛的ID
|
||||
int east_cow_id; // 参与该交叉点的东向牛的ID
|
||||
|
||||
// 重载小于运算符,为sort函数提供排序规则
|
||||
// 这是这个算法思想的核心:按空间位置排序
|
||||
bool operator<(const Intersection& other) const {
|
||||
// 主关键字:按 x 坐标从小到大排序
|
||||
if (x != other.x) {
|
||||
return x < other.x;
|
||||
}
|
||||
// 次关键字:如果 x 相同,按 y 坐标从小到大排序
|
||||
return y < other.y;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
FAST_IO;
|
||||
|
||||
int N;
|
||||
std::cin >> N;
|
||||
|
||||
// 分别存储北向和东向的奶牛
|
||||
std::vector<Cow> north_cows;
|
||||
std::vector<Cow> east_cows;
|
||||
// 使用一个vector来存储所有奶牛的原始信息,方便通过ID快速查找
|
||||
std::vector<Cow> all_cows(N);
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
char dir;
|
||||
long long x, y;
|
||||
std::cin >> dir >> x >> y;
|
||||
all_cows[i] = {i, x, y, dir};
|
||||
if (dir == 'N') {
|
||||
north_cows.push_back({i, x, y, dir});
|
||||
} else {
|
||||
east_cows.push_back({i, x, y, dir});
|
||||
}
|
||||
}
|
||||
|
||||
// --- 步骤 1: 生成所有潜在的交叉点 ---
|
||||
std::vector<Intersection> intersections;
|
||||
for (const auto& n_cow : north_cows) {
|
||||
for (const auto& e_cow : east_cows) {
|
||||
// 一个北向牛和一个东向牛要相遇,必须满足几何条件:
|
||||
// 北向牛在东向牛的右边 (n_cow.x > e_cow.x)
|
||||
// 且北向牛在东向牛的下边 (n_cow.y < e_cow.y)
|
||||
if (n_cow.x > e_cow.x && n_cow.y < e_cow.y) {
|
||||
intersections.push_back({n_cow.x, e_cow.y, n_cow.id, e_cow.id});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- 步骤 2: 按扫描线顺序对所有交叉点进行排序 ---
|
||||
// 这是算法的关键!保证了我们总是处理路径上“最先”遇到的障碍
|
||||
std::sort(intersections.begin(), intersections.end());
|
||||
|
||||
// --- 步骤 3: 模拟处理排序后的交叉点 ---
|
||||
|
||||
// `blame`数组既存储最终结果,也动态更新
|
||||
// `blame[i]` = 牛i直接或间接阻挡的奶牛总数
|
||||
std::vector<int> blame(N, 0);
|
||||
// `stopped`数组标记一头牛是否已经停止
|
||||
std::vector<bool> stopped(N, false);
|
||||
|
||||
for (const auto& intersect : intersections) {
|
||||
int n_id = intersect.north_cow_id;
|
||||
int e_id = intersect.east_cow_id;
|
||||
|
||||
// 如果参与这个交叉点的两头牛中,有任何一头已经停下了,
|
||||
// 那么这个交叉点上的碰撞就不会发生,直接跳过。
|
||||
if (stopped[n_id] || stopped[e_id]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 计算两头牛到达交叉点所需的距离(也即时间,因为速度为1)
|
||||
long long dist_n = intersect.y - all_cows[n_id].y; // 北向牛需要向北走的距离
|
||||
long long dist_e = intersect.x - all_cows[e_id].x; // 东向牛需要向东走的距离
|
||||
|
||||
if (dist_e < dist_n) { // 东向牛先到,阻挡北向牛
|
||||
stopped[n_id] = true; // 北向牛被阻挡,标记为停止
|
||||
|
||||
// 关键的责备计算:
|
||||
// 东向牛的责备数 += 1 (被它直接阻挡的北向牛) + 北向牛原本的责备数
|
||||
// 这是一种动态规划的思想,利用了正确的处理顺序,
|
||||
// 使得 `blame[n_id]` 此时已经包含了n_id能阻挡的所有下游奶牛。
|
||||
blame[e_id] += 1 + blame[n_id];
|
||||
|
||||
} else if (dist_n < dist_e) { // 北向牛先到,阻挡东向牛
|
||||
stopped[e_id] = true; // 东向牛被阻挡,标记为停止
|
||||
|
||||
// 同理,更新北向牛的责备数
|
||||
blame[n_id] += 1 + blame[e_id];
|
||||
}
|
||||
// 如果 `dist_n == dist_e`,两牛同时到达,擦肩而过,互不影响,不做任何处理。
|
||||
}
|
||||
|
||||
// --- 步骤 4: 输出结果 ---
|
||||
// 按照原始输入顺序 (0 to N-1) 输出每头牛的责备数
|
||||
for (int i = 0; i < N; ++i) {
|
||||
std::cout << blame[i] << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user