专栏文章
题解:CF2045M Mirror Maze
CF2045M题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miomuscp
- 此快照首次捕获于
- 2025/12/02 21:47 3 个月前
- 此快照最后确认于
- 2025/12/02 21:47 3 个月前
不想写搜索怎么办?来写并查集吧!
题目描述
给定一个 行 列的网格。该网格中的每个方格要么为空,要么在方格的一条对角线上有一面镜子。每面镜子由一条线段表示;所有镜子遵循反射定律。

找出所有在网格外沿的位置,满足在该位置放置一个激光发射器,其激光束能击中所有的镜子。如下图所示:

解题思路
记 为 上数第 行 左数第 列 的格子的 东/西/南/北 边缘,其中 。不难得出 与 等价,其它等价式子同理。
对于每个格子 ,分类讨论:
- 若其没有镜子,则连边 和 ;
- 若其镜子方向为 左上——右下,则连边 和 ;
- 若其镜子方向为 右上——左下,则连边 和 。
使用并查集维护所有连通块,并计算出每个连通块所经过镜子的数量。
具体地,记点 的祖先为 ,维护所有 (初值为 )。对于每个有镜子的格子 ,假设镜子方向为 左上——右下(反之同理),分类讨论:
具体地,记点 的祖先为 ,维护所有 (初值为 )。对于每个有镜子的格子 ,假设镜子方向为 左上——右下(反之同理),分类讨论:
- 若 ,则令 。
- 若 ,则仅令 。
枚举所有在网格外沿的点(形如 ),若其祖先的 值恰好为镜子总数,则将其输出即可。
参考代码
CPP#include <bits/stdc++.h>
using namespace std;
const int MAXP = 1e5 + 10;
int n, m;
char s[210][210];
int fa[MAXP], cnt[MAXP];
vector<string> ans;
// 1234 = NSWE.
inline int num(int i, int j, int d)
{return d == 1 ? (i - 1) * m + j :
d == 2 ? i * m + j :
(n + 1) * m + (i - 1) * (m + 1) + j + (d == 4);}
inline int find(int u)
{return fa[u] == u ? u : fa[u] = find(fa[u]);}
inline void un_(int u, int v)
{fa[find(u)] = find(v);}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
for (int i = 1; i < MAXP; i++) fa[i] = i;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (s[i][j] == '.')
un_(num(i, j, 1), num(i, j, 2)), un_(num(i, j, 3), num(i, j, 4));
else if (s[i][j] == '/')
un_(num(i, j, 1), num(i, j, 3)), un_(num(i, j, 2), num(i, j, 4));
else
un_(num(i, j, 1), num(i, j, 4)), un_(num(i, j, 2), num(i, j, 3));
}
int tot = 0;
for (int i = 1; i <= n; i++)
for (int j = 1, j1, j2; j <= m; j++)
{
if (s[i][j] == '.') continue;
tot++;
if (s[i][j] == '/') j1 = num(i, j, 1), j2 = num(i, j, 2);
else j1 = num(i, j, 1), j2 = num(i, j, 3);
j1 = find(j1), j2 = find(j2);
cnt[j1]++; if (j1 != j2) cnt[j2]++;
}
for (int i = 1; i <= n; i++)
if (cnt[find(num(i, 1, 3))] == tot) ans.push_back("W" + to_string(i));
for (int i = 1; i <= n; i++)
if (cnt[find(num(i, m, 4))] == tot) ans.push_back("E" + to_string(i));
for (int i = 1; i <= m; i++)
if (cnt[find(num(1, i, 1))] == tot) ans.push_back("N" + to_string(i));
for (int i = 1; i <= m; i++)
if (cnt[find(num(n, i, 2))] == tot) ans.push_back("S" + to_string(i));
printf("%d\n", ans.size());
for (auto str : ans) printf("%s ", str.c_str());
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...