题目大意:
题目链接:https://loj.ac/problem/2686
在一片长方形的草地上,有2种动物——兔子和狐狸活动。兔子走过草地会留下R,狐狸走过草地会留下 F。每只动物从左上角进入草地,从右下角走出草地。其间,它可以上下左右乱跳(可以重复),经过的格子会被覆盖上它的脚印。每次草地上最多只有一只动物。
........ RRR..... FFR.....
........ ..RRR... .FRRR...
........ ..R..... .FFFFF..
........ ..RRRR.R ..RRRFFR
........ .....RRR .....FFF
给你地图,问最少有多少只动物走过了草地。
思路:
比较显然的是:倘若一种动物至少有两只,那么说明另一种动物将这种动物的足迹分成了两部分。
为了使答案尽量小,我们不妨设最后一只动物走过的路径倒数第二只动物也全部走过,同理第
n
−
1
n-1
n−1只动物一定走过第
n
n
n只动物走的路径。
那么暴力的思想就是把连接左上角和右下角的连通块全部取反,形成一个新的图,然后再进行上述操作。记录操作次数即为答案。
但是这样的时间复杂度太高了。我们发现其实没有必要取反,因为取反了再取连通块也会把这些已取反的点取走。直接从这个连通块的边界开始搜。这样可以保证每个点只进入队列一次,时间复杂度约为
O
(
n
m
)
O(nm)
O(nm)。
本题需卡常。
代码:
#include <queue>
#include <cstdio>
#define mp make_pair
using namespace std;
const int N=4010;
const int dx[]={0,0,0,-1,1};
const int dy[]={0,-1,1,0,0};
int n,m,ans;
char ch[N][N];
bool vis[N][N];
queue<pair<int,int> > q[2];
bool bfs(int id)
{
bool flag=0;
while (q[id].size())
{
int x=q[id].front().first,y=q[id].front().second;
q[id].pop();
for (int i=1;i<=4;i++)
{
int xx=x+dx[i],yy=y+dy[i];
if (xx<1||xx>n||yy<1||yy>m||vis[xx][yy]||ch[xx][yy]=='.') continue;
if (ch[xx][yy]==ch[x][y]) q[id].push(mp(xx,yy));
else q[id^1].push(mp(xx,yy)),flag=1;
vis[xx][yy]=1;
}
}
return flag;
}
void work()
{
q[0].push(mp(1,1));
vis[1][1]=1;
ans=1;
for (int i=0;;i^=1,ans++)
if (!bfs(i)) break;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
while (ch[i][j]=getchar())
if (ch[i][j]=='.'||ch[i][j]=='F'||ch[i][j]=='R') break;
work();
printf("%d\n",ans);
return 0;
}