0%

1929.镜子田地

1929. 镜子田地

题目描述:

农夫约翰在屋子外面放了一些旧镜子,他的奶牛们像往常一样调皮地偷走了它们!

奶牛们将镜子放置在了一个矩形田地中,该田地可被划分为 $ N×M $ 个方格区域。

在每个方格区域中,奶牛在其某对对角之间放置一个双面镜,因此,共有两种放法,一种为 / 放置(镜子连接方格左下角和右上角),另一种为 \ 放置(镜子连接方格左上角和右下角)。

一天晚上,奶牛贝茜将激光发射器带到了该田地中。

她站在田地外面,沿着田地的行或列水平或垂直照射光束,使光束反射一定数量的镜子。

由于镜子都是沿对角线摆放,因此经反射镜反射的水平光束最终将垂直传播,反之亦然。

贝茜想知道从田地之外射入的水平或垂直光束最多可以在田地中被反射多少次。

给定镜子田地的布局,请帮助贝茜计算这个数字。

输入格式

第一行包含 $ N $ 和 $ M $ 。

接下来 $ N $ 行,每行包含 $ M $ 个 /\ 字符,表示田地中镜子的具体摆放方式。

输出格式

输出田地之外的水平或垂直光束能够被反射的最大次数。

如果可以无限反射,则输出 $ −1 $ 。

数据范围

$ 1≤N,M≤1000 $

输入样例:

1
2
3
4
3 3
/\\
\\\
/\/

输出样例:

1
3

样例解释

贝茜可以从上向下沿中间列上方发射激光。

共可以反射 $ 3 $ 次。

题解:

环图:图内全是简单环和简单路,并且互不相交。

一个图内结点的度数全小于等于 $ 2 $ ,就是环图。

证明:首先从度为 $ 1 $ 的结点出发,连接度为 $ 1 $ 的,得到简单路。连接度为 $ 2 $ 的,后面继续连接度为 $ 2 $ 的,后面不能连接到前面已经连接的度为 $ 2 $ 的结点上,因为那样的话前面的结点度变为了 $ 3 $ 。由于度为 $ 2 $ 的结点不是无限的,所以得到简单路。

度为 $ 2 $ 的结点出发只能得到一个环。度为 $ 0 $ 的忽略。

如果一个图内结点的度全是 $ 2 $ ,内部只能全是简单环,而且不相交。

这个图,每个格子可以看做两个点,镜子一面是一个点,另一面是另一个点,而且内部的格子度为 $ 2 $ ,边缘的格子度为 $ 1 $ ,是一个环图。这样的话就简单了,只需要 dfs 得到最长的路就行了。

dfs 方向设置也有技巧,由于两个方向可逆,所以可以考虑使用异或。

假如这样的话 $ \uparrow:0, \rightarrow: 1,\downarrow:2, \leftarrow:3 $

$ 0 \leftrightarrow 1, 2 \leftrightarrow 3, / $ 可以直接异或 $ 1 $ 实现。

$ 0\leftrightarrow3, 1 \leftrightarrow 2, \setminus $ 可以直接异或 $ 3 $ 实现。


$ 0 \leftrightarrow 2, 1 \leftrightarrow 3 $ 可以直接异或 $ 2 $ 实现。

所以与如何设置方向无关,都可以异或回来。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
using namespace std;
using namespace FAST_IO;
const ll mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll INF_LL = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-5;
const int maxn = 1e3 + 10;
const int maxm = 1e5 + 10;
int t, n, m, k;
char g[maxn][maxn];
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int dfs(int x, int y, int dir)
{
if (x < 0 || x >= n || y < 0 || y >= m)
return 0;
if (g[x][y] == '/')
{
dir ^= 1;
}
else
{
dir ^= 3;
}
x += dx[dir];
y += dy[dir];
return dfs(x, y, dir) + 1;
}
int main()
{
// #define COMP_DATA
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
for (int i = 0; i < n; i++)
{
cin >> g[i];
}
int ans = 0;
for (int i = 0; i < n; i++)
{
ans = max(ans, dfs(i, 0, 1));
ans = max(ans, dfs(i, m - 1, 3));
}
for (int i = 0; i < m; i++)
{
ans = max(ans, dfs(0, i, 2));
ans = max(ans, dfs(n - 1, i, 0));
}
cout << ans << endl;
return 0;
}