题目链接:http://acm.uestc.edu.cn/#/problem/show/1086
直接搜会超时…显然,我居然还试了一发….
所以要用记忆化搜索。
每一个点有四种到达方式,上,右,下,左,每种又分为在这一个点下一步应该往左走还是往右走。所以一个点共有八种状态,开数组,记忆每一个点在每一种状态能走多远距离,就可以避免重复搜索。
参考博客:http://blog.csdn.net/code12hour/article/details/50915963 感谢!
方向的数组dx、dy的意义:
dx[0]和dx[4]表示面向上时向右走和向左走。
dx[1]和dx[5]表示面向右时向右走和向左走。
dx[2]和dx[6]表示面向下时向右走和向左走。
dx[3]和dx[7]表示面向左时向右走和向左走。
而0 - 7则表示八种状态。
dfs的参数s即表示状态号(0 - 7),(s + 4)% 8 即可得到下一步的状态。
这题有个坑点,我不太懂为什么,读入地图的时候如果按照字符一个一个地读入,并且用getchar读回车的话会直接WA,更奇怪的是在vj上的样例这么读过不了,但是OJ上的样例却能过….难道它们不一样吗….
而改成用scanf(“%s”, str)每次读一行就没问题了,这是因为数据不规范吗?不是很懂…..
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 1010;
int N, M;
char map[maxn][maxn];
int sta[maxn][maxn][8];
int dx[8] = {0, 1, 0, -1, -1, 0, 1, 0};
int dy[8] = {1, 0, -1, 0, 0, 1, 0, -1};
int dfs(int x, int y, int s) {
if(x < 1 || x > N || y < 1 || y > M) return 0;
if(map[x][y] == '0') return sta[x][y][s] = 0;
if(sta[x][y][s] != -1) return sta[x][y][s];
return sta[x][y][s] = 1 + dfs(x + dx[s], y + dy[s], (s + 4) % 8); //(s + 4) % 8为下一步的状态
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%d %d", &N, &M);
getchar();
int i, j, k;
char str[maxn];
for(i = 1; i <= N; i++) {
scanf("%s", str);
for(j = 1, k = 0; j <= M; j++, k++) {
map[i][j] = str[k];
}
}
memset(sta, -1, sizeof(sta)); //初始化为-1
int ans = 0;
for(i = 1; i <= N; i++) {
for(j = 1; j <= M; j++) {
if(map[i][j] == '1') {
int res = 1;
res += dfs(i - 1, j, 0); //四个方向分别搜索,上右下左
res += dfs(i, j + 1, 1);
res += dfs(i + 1, j, 2);
res += dfs(i, j - 1, 3);
if(res > ans) ans = res;
}
}
}
printf("%d\n", ans);
}
return 0;
}