题目
描述
Little Hi gets lost in the city. He does not know where he is. He does not know which direction is north.
Fortunately, Little Hi has a map of the city. The map can be considered as a grid of NM blocks. Each block is numbered by a pair of integers. The block at the north-west corner is (1, 1) and the one at the south-east corner is (N, M). Each block is represented by a character, describing the construction on that block: '.' for empty area, 'P' for parks, 'H' for houses, 'S' for streets, 'M' for malls, 'G' for government buildings, 'T' for trees and etc.
Given the blocks of 33 area that surrounding Little Hi(Little Hi is at the middle block of the 3*3 area), please find out the position of him. Note that Little Hi is disoriented, the upper side of the surrounding area may be actually north side, south side, east side or west side.
输入
Line 1: two integers, N and M(3 <= N, M <= 200).
Line 2~N+1: each line contains M characters, describing the city's map. The characters can only be 'A'-'Z' or '.'.
Line N+2~N+4: each line 3 characters, describing the area surrounding Little Hi.
输出
Line 1~K: each line contains 2 integers X and Y, indicating that block (X, Y) may be Little Hi's position. If there are multiple possible blocks, output them from north to south, west to east.
样例
样例输入
8 8
...HSH..
...HSM..
...HST..
...HSPP.
PPGHSPPT
PPSSSSSS
..MMSHHH
..MMSH..
SSS
SHG
SH.
样例输出
5 4
分析
这题感觉有几处坑,分别是:小地图的方向是不固定的、可旋转的;输出的结果可能会不止一个。网站给此题贴的标签是“枚举”。我的做法是,除去大地图最外面一圈,然后在剩下的部分找出小地图的中心点。找到一个中心点以后,要判断该中心点外面一圈的8个字符是否和小地图的一致。无论大小地图,中心点外围的字符我都是用死方法获得的,就是构造了一个长度为8的数组,然后根据外围8个字符与中心点的关系获取并储存到数组中。
为了解决小地图可旋转的问题,我是在获取小地图外围字符后紧接着,用了一个循环使得每次下来字符数组的0号元素被移到最后,因为数组长为8,于是这样得到8个数组,包含了所有可能的旋转情况。再用大地图获取的数据一比较,就可以判断大地图上的中心点是否最终要求的点啦。
C#代码写了大概70行,虽然不长,但是通过这题,还是对C#一些语法细节有了更好的了解。比如字符串的截取方法Substring(起点, 截取长度),字符串的搜索IndexOf(搜索内容, 起点),用于比较两个数组内元素是否相同、返回一个布尔值的CenterAroundItem.OrderBy(a => a).SequenceEqual(searchArround.OrderBy(a => a))(此处用到了System.Linq,还不是很了解,是一个要填的大坑)。
代码
写了一个下午,终于AC了orz。水平有限,多年以后看自己的代码会不会想骂写以下代码的自己哈哈哈。
using System;
using System.Linq;
class Program
{
static void Main(string[] args)
{
string[] NM = (Console.ReadLine()).Split(' ');
int N = Convert.ToInt32(NM[0]);
int M = Convert.ToInt32(NM[1]);
string[] map = new string[N];
for (int i = 1; i <= N; i++)
{
map[i - 1] = Console.ReadLine();
}
string[] locate = new string[3];
for (int i = 1; i <= 3; i++)
{
locate[i - 1] = Console.ReadLine();
}
string centerPoint = locate[1].Substring(1, 1);
string[] centerAround = {locate[0].Substring(0,1), locate[0].Substring(1, 1), locate[0].Substring(2, 1),
locate[1].Substring(0,1),locate[1].Substring(2,1),
locate[2].Substring(0,1),locate[2].Substring(1,1),locate[2].Substring(2,1)};
string temp;
string[][] allCenterAround = new string[8][];
for (int j = 0; j < centerAround.Length; j++)
{
for (int k = 0; k < centerAround.Length; k++)
{
if (k + 1 < centerAround.Length)
{
temp = centerAround[k];
centerAround[k] = centerAround[k + 1];
centerAround[k + 1] = temp;
}
}
allCenterAround[j] = centerAround;
}
for (int i = 1; i < N - 1; i++)
{
int search = map[i].IndexOf(centerPoint, 1);
while (search <= M - 2 && search != -1)
{
string[] searchArround = {map[i-1].Substring(search-1,1), map[i - 1].Substring(search, 1), map[i - 1].Substring(search + 1, 1),
map[i].Substring(search-1,1),map[i].Substring(search+1,1),
map[i+1].Substring(search-1,1),map[i+1].Substring(search,1),map[i+1].Substring(search+1,1)};
foreach (string[] CenterAroundItem in allCenterAround)
{
if (CenterAroundItem.OrderBy(a => a).SequenceEqual(searchArround.OrderBy(a => a)))
{
Console.WriteLine((i + 1) + " " + (search + 1));
break;
}
}
search = map[i].IndexOf(centerPoint, search + 1);
}
}
}
}
体会
啊啊我居然也感受到了AC的快感!之前没有意识到要刷这些算法题,不过现在为时未晚,重在坚持。
不过C#的效率也是让我大跌眼睛的。一个朋友用C++做这道题目,和我的算法差不多,但是程序跑的时间和占用内存方面都优于我的(见上图)。嗯……他的程序跑样例的时间为2ms,占用内存为几kb。C++的效率真的不服不行。但我个人还是很享受用C#编程的,感觉语法上更加容易理解,而且对程序员更加友好?不过目前的大学课程安排的是学习Java,或许我迟点有空会用Java把这题重新做一遍吧。
昨晚的微软预科生校招笔试,把我虐得怀疑人生。不过受到刺激也不失为一件好事,让我意识到自己在算法上面的短板,希望下一年做的时候能够得心应手一点点吧。