UESTC 1086 邱老师降临小行星 (记忆化搜索)

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


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值