题目链接:https://leetcode-cn.com/problems/Db3wC1/
题目大意
给出一个
N
∗
M
∗
T
N*M*T
N∗M∗T的图,有障碍物和道路,一共有T个时刻,每个时刻图会变成对应时刻的样子,每个时刻可以往相邻的格子走一步或停留,问是否能在T时刻内从左上方走到右下方
可以选择一个障碍物消除一个时刻,以及选择一个位置的障碍物永久消除
题解
永久消除说明可能多次经过该点,与停留在该点等价
d
p
[
t
]
[
x
]
[
y
]
[
p
1
]
[
p
2
]
表
示
t
时
刻
,
在
位
置
(
x
,
y
)
dp[t][x][y][p1][p2]表示t时刻,在位置(x,y)
dp[t][x][y][p1][p2]表示t时刻,在位置(x,y)
p
1
,
p
2
表
示
两
个
消
除
是
否
已
经
使
用
p1,p2表示两个消除是否已经使用
p1,p2表示两个消除是否已经使用
时间从后往前倒着走
初始值
d
p
[
T
−
1
]
[
N
−
1
]
[
M
−
1
]
[
0
]
[
0
]
=
1
,
其
余
为
0
dp[T-1][N-1][M-1][0][0]=1,其余为0
dp[T−1][N−1][M−1][0][0]=1,其余为0
转移方程
(
x
,
y
)
−
>
(
p
x
,
p
y
)
(x,y)->(px,py)
(x,y)−>(px,py)
(
p
x
,
p
y
)
=
′
.
′
:
d
p
[
t
]
[
p
x
]
[
p
y
]
[
p
1
]
[
p
2
]
∣
=
d
p
[
t
+
1
]
[
p
x
]
[
p
y
]
[
p
1
]
[
p
2
]
(px,py)='.':dp[t][px][py][p1][p2]|=dp[t+1][px][py][p1][p2]
(px,py)=′.′:dp[t][px][py][p1][p2]∣=dp[t+1][px][py][p1][p2]
(
p
x
,
p
y
)
=
′
#
′
:
(px,py)='\#':
(px,py)=′#′:
(
p
1
=
0
)
:
d
p
[
t
]
[
p
x
]
[
p
y
]
[
1
]
[
p
2
]
∣
=
d
p
[
t
+
1
]
[
x
]
[
y
]
[
p
1
]
[
p
2
]
\ \ (p1=0):dp[t][px][py][1][p2]|=dp[t+1][x][y][p1][p2]
(p1=0):dp[t][px][py][1][p2]∣=dp[t+1][x][y][p1][p2]
(
p
2
=
0
)
:
d
p
[
t
]
[
p
x
]
[
p
y
]
[
p
1
]
[
1
]
∣
=
d
p
[
t
+
k
]
[
x
]
[
y
]
[
p
1
]
[
p
2
]
(
1
≤
k
≤
n
−
t
−
1
)
\ \ (p2=0):dp[t][px][py][p1][1]|=dp[t+k][x][y][p1][p2](1\leq k\leq n-t-1)
(p2=0):dp[t][px][py][p1][1]∣=dp[t+k][x][y][p1][p2](1≤k≤n−t−1)
发现永久消除转移的时候时间复杂度过高,但可以后缀和处理
令
s
d
[
t
]
[
x
]
[
y
]
[
p
1
]
=
m
a
x
t
≤
k
≤
T
−
1
(
d
p
[
k
]
[
x
]
[
y
]
[
p
1
]
[
0
]
)
sd[t][x][y][p1]=max_{t\leq k\leq T-1}(dp[k][x][y][p1][0])
sd[t][x][y][p1]=maxt≤k≤T−1(dp[k][x][y][p1][0])
则转移为
(
p
2
=
0
)
:
d
p
[
t
]
[
p
x
]
[
p
y
]
[
p
1
]
[
1
]
∣
=
s
d
[
t
+
1
]
[
x
]
[
y
]
[
p
1
]
\ \ (p2=0):dp[t][px][py][p1][1]|=sd[t+1][x][y][p1]
(p2=0):dp[t][px][py][p1][1]∣=sd[t+1][x][y][p1]
复杂度压制到
O
(
T
N
M
)
O(TNM)
O(TNM)
进一步可以压位dp和sd,以节省空间
代码
#define ms(a) memset(a, 0, sizeof(a))
bool dp[101][50][50][2][2];
bool sd[101][50][50][2];
int dx[5] = {0, 1, -1, 0, 0};
int dy[5] = {0, 0, 0, 1, -1};
int T, n, m;
class Solution
{
public:
bool escapeMaze(vector<vector<string>> &maze)
{
ms(dp);
ms(sd);
T = maze.size();
n = maze[0].size();
m = maze[0][0].length();
dp[T - 1][n - 1][m - 1][0][0] = sd[T - 1][n - 1][m - 1][0] = true;
for (int t = T - 2; t >= 0; t--)
{
for (int x = 0; x < n; x++)
for (int y = 0; y < m; y++)
for (int p1 = 0; p1 < 2; p1++)
for (int p2 = 0; p2 < 2; p2++)
{
for (int i = 0; i < 5; i++)
{
int px = x + dx[i], py = y + dy[i];
if (px >= 0 && px < n && py >= 0 && py < m)
{
if (maze[t][px][py] == '.')
{
dp[t][px][py][p1][p2] |= dp[t + 1][x][y][p1][p2];
}
else
{
if (!p1)
dp[t][px][py][1][p2] |= dp[t + 1][x][y][p1][p2];
if (!p2)
dp[t][px][py][p1][1] |= sd[t + 1][x][y][p1];
}
}
}
// if (dp[t][x][y][p1][p2])
// {
// int xxx = 0;
// }
}
for (int x = 0; x < n; x++)
for (int y = 0; y < m; y++)
for (int p1 = 0; p1 < 2; p1++)
{
sd[t][x][y][p1] = sd[t + 1][x][y][p1] | dp[t][x][y][p1][0];
// if (dp[t][x][y][p1][0])
// {
// int xxx = 0;
// }
}
}
bool ans = false;
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
if (dp[0][0][0][i][j])
ans = true;
return ans;
}
};