宝岛地图 (51Nod-1572)

题目来源:  CodeForces
基准时间限制:1 秒 空间限制:131072 KB 分值: 20  难度:3级算法题

勇敢的水手们到达了一个小岛,在这个小岛上,曾经有海盗在这里埋下了一些宝藏。然而,我们的船快抛锚了,与此同时,船长发现藏宝图的一角被老鼠咬掉了一块。

 

藏宝图可以用一个n×m大小的矩形表示。矩形中的每一小块表示小岛中的一小块陆地(方块的边长为1米)。有一些方块表示的是海,这些块人是不能通过的。除了海不能走,其它的小方块都是可以行走的。在可行走区域里有一些小方块表示一些已知的地点。

 

另外,在地图上有k条指令。每条指令的格式表示如下:

“向y方向走n米”。

 

这里的方向有四种:“北”,“南”,“东”,“西”。如果你正确的跟着这些指令行走,并且完整的执行完所有指令,你就可以找到宝藏所在的地点。

 

但是,很不幸,由于地图中好多地方都缺失了,船长也不知道从哪些地方开始走。但是船长依然清楚地记得一些已知的地点。另外,船长也知道所有可行走区域。

 

现在船长想知道从哪些已知地点出发,按照指令,可能找到宝藏所在地。


Input
单组测试数据
第一行包含两整数n和m(3≤n,m≤1000)。
接下来的n行每行有m个字符,表示整个地图。
“#”代表海。在地图矩形中,矩形的四周一圈一定是海。
“.”代表可行走区域,未知地点。大写字母“A”到“Z”表示可行走区域,已知地点。
所有大写字母不一定都被用到。每个字母在地图中最多出现一次。所有已知地点用不同的大写字母表示。

接下来一行有一个整数k(1≤k≤10^5),接下来有k行。
每行表示一条指令。
指令格式为“dir len”,“dir”表示朝哪个方向走,“len”表示走几步。
“dir”有四种取值“N”,“S”,“E”,“W”,对应题目中的“北”,“南”,“东”,“西”
在地图中,北是在顶部,南是在底部,西是在左边,东是在右边。“len”是一个整数,范围在[1,1000]。
Output
共一行,按字典序升序打印出所有可以完整执行地图中指令的已知区域的字母,如果没有满足要求的已知区域,则打印“no solution”(没有引号)。
Input示例
输入样例1
6 10
##########
#K#..#####
#.#..##.##
#..L.#...#
###D###A.#
##########
4
N 2
S 1
E 1
W 2
Output示例
输出样例1
AD
解题思路:其实这道题的方法有很多,我来说说我是怎么想的。
题目会给你一些操作,怎么走,当时就想,我一个个的走吧,可是会超时。于是我就知道了,我一个个的走,一定会走重复的点,所以超时,那么我能不能不走重复的点呢。那么每次操作都之前,我都可以用二分先找到这个方向走过和没走过的边界在哪里,这样就可以直接跳过去,不会再走重复的点了,时间也就能够剩下来了。
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
char  map[1010][1010];   //存入地图
int   book[2010][2010];   //标记走过的点
struct s{ 
	int i;
	int j;
}h[30];   //记录要走的字母有哪些
struct p{
	char c;     //要走的方向
	int len;   //要走的长度
}l[100010];
bool f(int x,int y)
{
	if(book[x][y]==0)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}
bool f1(int x,int y)
{
	if(book[x][y]==1)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}
int main()
{
	int n,m;
	int k=0;
	char ans[30];
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		getchar();
		for(int j=1;j<=m;j++)
	    {
	    	scanf("%c",&map[i][j]);
		if(map[i][j]>='A'&&map[i][j]<='Z')
		{
			h[k].i=i;
			h[k].j=j;
			k++;
		}
	}
	}
	int t;
	scanf("%d",&t);
	for(int i=0;i<t;i++)
	{
		getchar();
		scanf("%c%d",&l[i].c,&l[i].len);   //存入要走的操作
	}
	int o=0;
	for(int i=0;i<k;i++)
	{
		memset(book,0,sizeof(book));
		int temp_x=h[i].i;
		int temp_y=h[i].j;
		book[temp_x][temp_y]=1;
		int flag=0;
		for(int j=0;j<t;j++)
		{
			  if(flag==1)
			  {
			  	   break;
			  }
			 switch(l[j].c)
			 {
			 	case 'N':{       //向北寻找
			 		int le=1,r=temp_x;
			 		while(le<=r)
			 		{
			 		      int mid=(le+r)/2;
						  if(f(mid,temp_y))
						  {
						  	   r=mid-1;
						  }
						  else
						  {
						       le=mid+1;
						  }	
					}
					if((temp_x-le)>l[j].len)
					{
						temp_x-=l[j].len;
					}
					else
					{
						int temp=l[j].len;
						l[j].len=l[j].len-(temp_x-le);
						temp_x=le;
						for(int p=0;p<l[j].len;p++)
						{
							temp_x-=1;
							book[temp_x][temp_y]=1;
							if(map[temp_x][temp_y]=='#'||temp_x<1)
			        	    {
			        		flag=1;
			        		break;
						    }
						}
						l[j].len=temp;
					}
			 	    break;	
			    }
			    case 'S':{      //向南寻找
			    	int le=temp_x,r=n;
			 		while(le<=r)
			 		{
			 		      int mid=(le+r)/2;
						  if(f1(mid,temp_y))
						  {
						  	   r=mid-1;
						  }
						  else
						  {
						       le=mid+1;
						  }	
					}
					if(r-temp_x>l[j].len)
					{
						temp_x+=l[j].len;
					}
					else
					{
						int temp=l[j].len;
						l[j].len=l[j].len-(r-temp_x);
						temp_x=r;
						for(int p=0;p<l[j].len;p++)
						{
							temp_x+=1;
							book[temp_x][temp_y]=1;
							if(map[temp_x][temp_y]=='#'||temp_x>n)
			        	    {
			        		flag=1;
			        		break;
						    }
						}
							l[j].len=temp;
					}
			 	    break;	
				}
				case 'E':{    //向东寻找
					 int le=temp_y,r=m;
			 		while(le<=r)
			 		{
			 		      int mid=(le+r)/2;
						  if(f1(temp_x,mid))
						  {
						  	   r=mid-1;
						  }
						  else
						  {
						       le=mid+1;
						  }	
					}
					if(r-temp_y>l[j].len)
					{
						temp_y+=l[j].len;
					}
					else
					{
						int temp=l[j].len;
						l[j].len=l[j].len-(r-temp_y);
						temp_y=r;
						for(int p=0;p<l[j].len;p++)
						{
							temp_y+=1;
							book[temp_x][temp_y]=1;
							if(map[temp_x][temp_y]=='#'||temp_y>m)
			        	    {
			        		flag=1;
			        		break;
						    }
						}
							l[j].len=temp;
					}
			 	    break;	
				}
				case 'W':{      //向西寻找
					int le=1,r=temp_y;
			 		while(le<=r)
			 		{
			 		      int mid=(le+r)/2;
						  if(f(temp_x,mid))
						  {
						  	   r=mid-1;
						  }
						  else
						  {
						       le=mid+1;
						  }	
					}
					if(temp_y-le>l[j].len)
					{
						temp_y-=l[j].len;
					}
					else
					{
						int temp=l[j].len;
						l[j].len=l[j].len-(temp_y-le);
						temp_y=le;
						for(int p=0;p<l[j].len;p++)
						{
							temp_y-=1;
							book[temp_x][temp_y]=1;
							if(map[temp_x][temp_y]=='#'||temp_y<1)
			        	    {
			        		flag=1;
			        		break;
						    }
						}
							l[j].len=temp;
					}
			 	    break;	
				}
			 }
		}
		if(flag==0)
		{
			ans[o]=map[h[i].i][h[i].j];
			o++;
		}
	}
	if(o!=0)
	{
	sort(ans,ans+o);
	for(int i=0;i<o;i++)
	{
		if(i==o-1)
		{
			printf("%c\n",ans[i]);
			return 0;
		}
		printf("%c",ans[i]);
	}
	}
    else
    {
    	printf("no solution\n");
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值