【JZOJ3319】【LOJ2686】雪地踪迹【BFS】

题目大意:

题目链接:https://loj.ac/problem/2686
在一片长方形的草地上,有2种动物——兔子和狐狸活动。兔子走过草地会留下R,狐狸走过草地会留下 F。每只动物从左上角进入草地,从右下角走出草地。其间,它可以上下左右乱跳(可以重复),经过的格子会被覆盖上它的脚印。每次草地上最多只有一只动物。

........      RRR.....      FFR.....
........      ..RRR...      .FRRR...
........      ..R.....      .FFFFF..
........      ..RRRR.R      ..RRRFFR
........      .....RRR      .....FFF

给你地图,问最少有多少只动物走过了草地。


思路:

比较显然的是:倘若一种动物至少有两只,那么说明另一种动物将这种动物的足迹分成了两部分。
为了使答案尽量小,我们不妨设最后一只动物走过的路径倒数第二只动物也全部走过,同理第n1n-1只动物一定走过第nn只动物走的路径。
那么暴力的思想就是把连接左上角和右下角的连通块全部取反,形成一个新的图,然后再进行上述操作。记录操作次数即为答案。
但是这样的时间复杂度太高了。我们发现其实没有必要取反,因为取反了再取连通块也会把这些已取反的点取走。直接从这个连通块的边界开始搜。这样可以保证每个点只进入队列一次,时间复杂度约为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;
}
posted @ 2019-07-08 17:07  全OI最菜  阅读(162)  评论(0编辑  收藏  举报