Robot on the Board 2

题目大意


机器人站在一个$n\times m$大小的矩阵上,每个单元格都写有’L’、’R’、’U’和’D’当中的某一字符,表示机器人在此格移动方向——分别为左、右、上和下。

当走出矩阵或者走到已经访问过的单元格时停止移动。问,机器人从哪个单元格出发能移动的步数最多,输出单元格的坐标以及最大数量的步数。

解题思路


翻译一下题意即为,给定一个有向图,每个点的权值为$1$,且每个点只有一条出边,从某个点出发,每个点只能经过一次,求从何处出发所经过点的权值和最大,并求出最大值。

那么直接枚举每个点进行记忆化搜索即可,考虑到有环的存在,可以开个数组记录当前点的状态,如:$0$表示未被搜索到,$1$表示正在被搜索中,$2$表示已经被搜索过了。那么如果我们在搜索中遇到了状态为$1$的点就意味着碰到环了,此时记录一下环的大小即可。

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
#include <bits/stdc++.h>
#define maxn 4000100
typedef __int128_t int128;
using namespace std;
const double eps=1e-8;
int e[maxn],v[maxn],state[maxn];
int l=0,r=0;
inline int dfs(int x){
if(state[x]==2) return v[x];
if(state[x]==1){
int cur=1,u=e[x];
while(u!=x) ++cur,state[u]=2,u=e[u];
u=e[x];
while(u!=x) v[u]=cur,u=e[u];
state[x]=2; v[x]=cur;
return v[x];
}
state[x]=1;
dfs(e[x]);
if(state[x]!=2) v[x]=v[e[x]]+1,state[x]=2;
return v[x];
}
void solve(){
l=r+1; state[0]=2; //表示终点
int n,m,ans=0,res=0;
cin >> n >> m;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
++r;
char x; cin >> x;
if(x=='L'&&j!=1) e[r]=r-1;
if(x=='R'&&j!=m) e[r]=r+1;
if(x=='U'&&i!=1) e[r]=r-m;
if(x=='D'&&i!=n) e[r]=r+m;
}
}
for(int i=l;i<=r;++i){
if(ans<dfs(i)) ans=v[i],res=i-l+1;
}
cout << (res-1)/m+1 << ' ' << (res-1)%m+1 << ' ' << ans << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t; cin >> t;
while(t--){
solve();
}
return 0;
}

此外,还可以在$dfs$前把所有环找出来。不过这种做法较上一种做法效率较低,而且还碰到了某些$ub$错误(C++17能过,C++20不能过,,)。

代码如下:

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
55
56
57
58
59
60
61
62
63
64
65
#include <bits/stdc++.h>
#define maxn 2010
using namespace std;
const double eps=1e-8;
char g[maxn][maxn];
int v[maxn][maxn];
bool vis[maxn][maxn];
int n,m;
inline void check(int x,int y){
int tx=x,ty=y;
vector<pair<int,int>>path;
while(1){
if(tx<1||tx>n||ty<1||ty>m) return ;
if(vis[tx][ty]){
int cur=path.end()-find(path.begin(),path.end(),make_pair(tx,ty));
for(auto it=find(path.begin(),path.end(),make_pair(tx,ty));it!=path.end();++it) v[it->first][it->second]=cur;
return ;
}
vis[tx][ty]=1;
path.push_back({tx,ty});
if(g[tx][ty]=='U') tx--;
else if(g[tx][ty]=='D') tx++;
else if(g[tx][ty]=='L') ty--;
else if(g[tx][ty]=='R') ty++;
}
}
int dfs(int x,int y){
if(x<1||x>n||y<1||y>m) return 0;
if(v[x][y]) return v[x][y];
if(g[x][y]=='U') return v[x][y]=dfs(x-1,y)+1;
else if(g[x][y]=='D') return v[x][y]=dfs(x+1,y)+1;
else if(g[x][y]=='L') return v[x][y]=dfs(x,y-1)+1;
else if(g[x][y]=='R') return v[x][y]=dfs(x,y+1)+1;
return v[x][y];
}
void solve(){
cin >> n >> m;
int resx,resy,ans=0;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
cin >> g[i][j]; v[i][j]=0; vis[i][j]=false;
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(!vis[i][j]) check(i,j);
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
dfs(i,j);
if(ans<v[i][j]) ans=v[i][j],resx=i,resy=j;
}
}
cout << resx << ' ' << resy << ' ' << ans << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t; cin >> t;
while(t--){
solve();
}
return 0;
}