浙大校赛--G(模拟+思维)

G--Robot Cleaner I

思路:

就是模拟一下点的移动,注意的是移动的数量很大,所以要做一个判断,如果发现不断走过重复的路径,

就可以结束循环了,跳出循环的条件是:垃圾数量+1==vis[x][y](表示标记的次数,因为先标记,所以是垃圾数量+1,

详细的解释见代码,感谢lcf学长的细心讲解)。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn = 2002;
char ss[maxn],a[maxn][maxn];
int vis[maxn][maxn],cnt;
int f(int x,int y){
	return 81*(a[x][y]-'0')+27*(a[x-1][y]-'0')+9*(a[x+1][y]-'0')+3*(a[x][y-1]-'0')+(a[x][y+1]-'0');
}
void walk(int &x,int &y){
	int tp = f(x,y);
	if(ss[tp]=='I') return ;
	else if(ss[tp]=='U'&&a[x-1][y]!='1') x--;
	else if(ss[tp]=='D'&&a[x+1][y]!='1') x++;
	else if(ss[tp]=='L'&&a[x][y-1]!='1') y--;
	else if(ss[tp]=='R'&&a[x][y+1]!='1') y++;
	
	if(a[x][y]=='2'&&ss[tp]=='P'){
		cnt++;a[x][y] = '0';
	}
}
int main(void)
{
	int T,i,j,n,m,sx,sy;
	LL k; 
	scanf("%d",&T);
	while(T--){
		memset(vis,0,sizeof(vis));
		scanf("%d%d",&n,&m);
		scanf("%d%d%lld",&sx,&sy,&k);
		scanf("%s",ss);
		int fg = 0,len = strlen(ss);
		for(i=0;i<len;i++)
		if(ss[i]=='P'){
			fg=1;break;
		}
		if(!fg){
			printf("0");
			continue;
		}
		for(i=1;i<=n;i++) scanf("%s",a[i]+1);
		cnt = 0;//cnt表示捡到的垃圾的数量 
		while(k--){
			if(vis[sx][sy]==cnt+1) break;
			/*
			这里很重要,因为k太大,所以我们要提前保证循环能够退出,我们从一个节点开始走,每次走到下一个节点,
			最坏的打算就是每次走一个环,然后这个环上有1个垃圾,我们将它捡起来,然后我们再从走过的点开始,每次走到 
			下一个节点,由于原来的垃圾被捡走了,所以下一次经过之前垃圾位置的2变为0,所以之前的路径也发生了变化,
			所以我们又相当于走了一条新的路径,然后我们探寻这条新的路径上的垃圾,如果再次回到起点,发现垃圾数量没有
			发生变化(也就是这条路上没有捡到垃圾),就表示上一次的路径是白走了,因为没有捡到垃圾,就没有改变节点,
			下一次的路径也就不会发生变化,所以就不用再次去走新的路径了。
			当然,上面我们考虑的是这条路径上只有个垃圾的最坏情况,也可能这条路径上有多(num)个垃圾,我们一次可以将这些垃圾全都捡完,
			然后我们又开辟了num个新的到路,于是当我们再一次回到起点的时候我们再一次去探寻新的路径,寻找新的路径上有没有垃圾,如果走过
			num条新的路径后发现垃圾的数量还是没有发生变化,就可以判断下一次的路径与这一次的路径相同,就可以结束当前的路径了。
			------------------------------------------thanks to lcf 
			*/ 
			vis[sx][sy]++;
			if(a[sx][sy]!='1') walk(sx,sy);
		}
		printf("%d\n",cnt);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41829060/article/details/89336400