3319. 【BOI2013】雪地踪迹

63 篇文章 0 订阅
9 篇文章 0 订阅

Description

森林里有一片长方形的草地,在清晨的大雪过后被一层厚厚的积雪所掩盖(下图左)。

住在森林里的兔子和狐狸,穿越草地,都会在雪地上留下他们的踪迹。他们总是从左上角进入,并从右下角离开草地。在这两者之间,他们可以来回走动,在雪地里玩,甚至在同一个地方多次留下踪迹。在任何时候,最多只有一只动物在草地上,且所有的动物都只进入草地一次。这些动物的运动踪迹可以被简单的利用横纵坐标来描述。它们不会斜着走,也不会跳越一个单元格。当新的动物进入单元格,旧的足迹都将被新的足迹所覆盖。

例如,第一个兔子从左上角到右下角越过草地(图中)。在那之后,一只狐狸越过,则他的运动踪迹将会覆盖兔子的踪迹(图右)。



你将在一段时间后,得到一张描述草地上每个单元格的状态的地图。请写一个程序,计算可能出现的动物数目的最小值N。

Input

第一行包含两个整数H和W,表示草地地图的高度和宽度。接下来的H行W列描述了草地地图的状态。“.”表示未被踩踏过的草地;“R”表示兔子留下的踪迹;“F”表示狐狸留下的踪迹。草地上至少存在一条完整的踪迹。

Output

输出仅一行,输出可能留下踪迹的动物的最小数量N。(保证N>=1)

Sample Input

5 8

FFR.....

.FRRR...

.FFFFF..

..RRRFFR

.....FFF

Sample Output

2

Data Constraint

30%的数据满足:动物数N<=200,H,W<=500

100%的数据满足:1<=H,W<=4000

Solution

我们可以发现一个动物能覆盖的脚印要么是另一个动物,要么是空地。因为动物可以随便走出一个联通块,所以当我们找到一个动物的一条从起点到终点的路径后,我们可以直接将整一块走过的路线视为另一种动物的脚印,再重复此过程就能得到最小的动物种数。那么我们一种方法是直接暴力,每找到一种动物的路线时记录与它相邻的所有不同动物的联通块所在位置,再将所有联通块bz,再找联通块所相邻的不同动物的位置,以此类推,注意用bfs更好。另一种解法是直接将相邻的两种不同动物脚印位置连一条1的边,最后从(1,1)跑一边spfa,到达的任意一点的最大值即为所求。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define F(i,a,b) for(int i=a;i<=b;i++)
#define N 4010
using namespace std;
int n,m,tot,sum,l,r,bz[N][N],p[N][N],d[N*N][2],ans=1;
int f[N*N][2],g[N*N][2],fx[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
char c[N][N];
void add(int x,int y){
	l++;p[x][y]=1;
	g[l][0]=x;g[l][1]=y;
}
void bfs(int x1,int y1,int z){
	int i=1,j=1;d[1][0]=x1;d[1][1]=y1;bz[x1][y1]=1;sum++;
	while(i<=j){
		int x=d[i][0],y=d[i][1];i++;
		F(k,0,3){
			int xx=x+fx[k][0],yy=y+fx[k][1];
			if(xx>0&&yy>0&&xx<=n&&yy<=m&&!bz[xx][yy]&&c[xx][yy]!='.'){
				if(z){
					if(c[xx][yy]=='F'){sum+=(bz[xx][yy]=1);++j;d[j][0]=xx;d[j][1]=yy;}
					else{if(!p[xx][yy]) add(xx,yy);}
				}
				else{
					if(c[xx][yy]=='R'){sum+=(bz[xx][yy]=1);++j;d[j][0]=xx;d[j][1]=yy;}
					else{if(!p[xx][yy]) add(xx,yy);}
				}
			}
		}
	}
}
int main(){
	scanf("%d%d\n",&n,&m);
	F(i,1,n){
		F(j,1,m){
			c[i][j]=getchar();
			tot+=(c[i][j]!='.');
		}
		char ch=getchar();
	}
	l=0;
	bfs(1,1,c[1][1]=='F');
	while(sum<tot){
		F(i,1,l) f[i][0]=g[i][0],f[i][1]=g[i][1];r=l;l=0;
		F(i,1,r){int x=f[i][0],y=f[i][1];if(!bz[x][y]) bfs(x,y,c[x][y]=='F');}
		ans++;
	}
	printf("%d\n",ans);
	return 0;
}


作者:zsjzliziyang 
QQ:1634151125 
转载及修改请注明 
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/95104624

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值