CF 1613E. Crazy Robot(拓扑)

Linking


大意:

一个机器人处在 n*m 的格子中的起点位置,最终要走到终点位置。
格子中有些位置可走,有些位置不可走。
每次可以给出一个指令往一个方向走一格,但机器人却会在其余三个方向中挑一个能走的前进。
问,有多少个位置可以作为起点,能够通过若干指令让机器人走到终点?

思路:

如果能够到达终点的话,说明从终点出发,能够前进到一个点。这个点最多只有两个方向可以走,选择以一个方向作为指令,那么机器人便会向另一方向走。便会走到走向终点的路上。如此往复。

但并不只有这一种情况。完全可能有多个方向可以走,但是无论走哪个方向都会到达终点。

所以,就需要像拓扑排序一样,每从一条路径到达了这个点,就把这个点的入度-1。
当从终点出发到达一个点的入度已经为1或者2了,说明除了这个来时的方向最多只有一个方向,这时候用另一方向作为指令,便会走到能够到达终点的点。
之后,该点入队,继续扩展

Code:

const int N = 1000010, mod = 1e9+7;
int T, n, m;
map<PII,int> f,ru;
map<int,char> a[N];
int stx,sty;
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
struct node{
	int x,y;
	int frx,fry; //注意记录来时的点,防止重复跳转走。 
};

void pre()
{
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++)
		{
			int cnt=0;
			for(int d=0;d<4;d++)
			{
				int tx=i+dir[d][0],ty=j+dir[d][1];
				if(tx<1||tx>n||ty<1||ty>m||a[tx][ty]=='#') continue;
				cnt++;
			}
			ru[{i,j}]=cnt;
		}
	}
}

void bfs()
{
	f.clear();
	queue<node> que;
	que.push({stx,sty});
	
	while(que.size())
	{
		int x=que.front().x, y=que.front().y;
		int frx=que.front().frx,fry=que.front().fry;
		que.pop();
		
		for(int i=0;i<4;i++)
		{
			int tx=x+dir[i][0],ty=y+dir[i][1];
			if(tx<1||tx>n||ty<1||ty>m||a[tx][ty]=='#'||a[tx][ty]=='+'||tx==frx&&ty==fry) continue;
			
			ru[{tx,ty}]--;
			
			if(ru[{tx,ty}]==1||ru[{tx,ty}]==0)
			{
				que.push({tx,ty,x,y});
				if(a[tx][ty]=='.') a[tx][ty]='+';
			}
		}
	}
}

int main(){
	Ios;
	
	cin>>T;
	while(T--)
	{
		cin>>n>>m;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++){
				cin>>a[i][j];
				if(a[i][j]=='L') stx=i,sty=j;
			}
		
		pre();
		bfs();
		
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				cout<<a[i][j];
			}
			cout<<"\n";
		}
	}
	
	return 0;
}

挺好的一道题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值