题意:
给定一个n*m的矩阵,每个格子中写有L、R、U、D这4种字符中的其中一种,表示下一步要走的方向
保证按照这个方向走不会走到矩阵外面,即保证不会越界
每个格子还有0、1两种颜色,0表示黑色,1表示白色
现在要求你在某些网格上摆放机器人,然后机器人将按照网格上的方向不断移动,
问最多摆放多少机器人,使得这些机器人在无限次的移动过程中不会出现两个机器人出现在同一个格子上
如果有多种方案能够使得机器人最多,那么选择能够摆放较多黑色格子的方案
输出最多摆放的机器人数以及该方案的黑色格子数
解法:
模拟或思考一下就会发现,网格图可以变为一个或多个不相交的循环路线。
对于每个循环路线,如果两个机器人从不同的位置出发,途中走到了同一个点,
显然他们之后的路径将相同,类似于合并成了一个点,
题目要求不能重合,那么这两个位置不能同时放机器人,我们取其中一个即可,优先取黑色
从上面可以看出,多个不能同时放机器人的网格有一个相同特征,就是足够多次移动之后终点相同
因为网格是nm的,那么走至少nm步之后,不能同时放机器人的位置就会合并为一个,
因为他们终点的唯一性,我们将终点标记,标明这个点能够到达机器人,同时标记机器人的颜色
只需要在每个点都放上一个机器人,然后走上n*m步(或者更多步),
最后被标记的终点数量就是最多能放置的最大机器人数量,
如果被标记的点上还标记了黑色,表明是某个黑色格子的终点,那么可以取黑色,否则只能取白色
遍历一遍所有格子就能统计出答案了。
计算出一个点走x步之后会到哪个点可以用倍增来做。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e6+5;
int nt[maxm][25],maxd=20;
int w[maxm],b[maxm];
char c[maxm];
char d[maxm];
int n,m;
int id(int i,int j){
return (i-1)*m+j;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
int T;cin>>T;
while(T--){
cin>>n>>m;
for(int i=1;i<=n*m;i++)cin>>c[i];
for(int i=1;i<=n*m;i++)cin>>d[i];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int x=id(i,j);
if(d[x]=='L'){
nt[x][0]=id(i,j-1);
}else if(d[x]=='R'){
nt[x][0]=id(i,j+1);
}else if(d[x]=='U'){
nt[x][0]=id(i-1,j);
}else if(d[x]=='D'){
nt[x][0]=id(i+1,j);
}
}
}
for(int j=1;j<=maxd;j++){//倍增计算nt数组
for(int i=1;i<=n*m;i++){
nt[i][j]=nt[nt[i][j-1]][j-1];
}
}
int step=maxm;//设定步数,大于等于n*m的都行
for(int i=1;i<=n*m;i++)w[i]=b[i]=0;
for(int i=1;i<=n*m;i++){
int now=i;
for(int j=maxd;j>=0;j--){//倍增走到终点
if(step>>j&1)now=nt[now][j];
}
if(c[i]=='0')b[now]=1;
else w[now]=1;
}
int ans1=0,ans2=0;
for(int i=1;i<=n*m;i++){
if(b[i])ans1++,ans2++;
else if(w[i])ans1++;
}
cout<<ans1<<' '<<ans2<<endl;
}
return 0;
}