题目链接: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; }