来自风平浪静的明天 (记忆化搜索 dp)

来自风平浪静的明天

【题目描述】
冬眠了五年,光终于从梦中醒来。
千咲、要,大家都在。
隐约记得“昨天”的海船祭,爱花意外成为贡女,沉入海底。
海面冰封,却有丝丝暖流在冰面之下涌动。
此时,爱花沉睡在祭海女神的墓地。她的胞衣在一点点脱落,化作一簇簇暖流,夹杂着她的感情,向海面上涌去。
爱花,你在哪里?
五年之后,纺已经成为海洋学研究科的大学生。
在纺的帮助下,光得知了海面下海流的情况。
纺告诉光,暖流一旦产生,就会不断地向四周扩散,直到遇到海中的岩石。
红腹海牛,快告诉光,爱花在哪里。
纺帮你绘制了一张海流情况图,长度为N,宽度为M。
海很大,一边有沙滩,一边一望无际,但长度和宽度都不会超过300。沙滩是金黄色的,所以用Y表示。海是蓝色的,所以用B表示。暖流很暖和,所以用H表示
海中有大大小小的石头。石头很危险,所以用X表示
光相信自己一定能找到爱花(爱花的位置只有一种可能)

【输入格式】
第一行包括两个整数N,M。
接下来N行,每行M个字符。

【输出格式】
仅一行,表示爱花的位置(如果你无能为力,请输出 -1 ,只要你尽力,光不会责怪你)

【样例输入】
5 5
YYYHB
YYHHH
YHHXB
BBHBB
BBBBB

【样例输出】
2 3

【数据范围】
对于30%的数据,n,m<=10
对于70%的数据,n,m<=100
对于100%的数据,n,m<=300

【样例解释】
在(2,3)出现第一个H后,经过3s后,出现样例输入的地图。
P.S. Mushroom拜托他GF出的这题= =

思路:
看看数据范围,应该是一个n^3的算法,x,y一枚举就n^2了,然后。。。发现H最多就会漫延n+m次。
用dp[step][x][y]表示当前在(x,y),还要走step步是否能达到目标局面,也就是说是个bool。
那么对于当前这个点,如果是’B’并且step!=0那么当前状态显然是false,如果是石头或者沙滩,那么是true,如果当前step==0,那么返回(g[x][y]==’H’)。
数据太水,暴力dfs可过。。。

std的题解:
Solution
还记得以前解决过的那个问题吗?
水从一个点开始向四周漫去,一定时间后是什么样子?
显然是简单的模拟。
这次的问题正好相反,要找到水开始漫的位置。

Solution1
看了半天,什么也没发现。
天空突然电闪雷鸣,一个神奇的想法也就出现了。
YYYHB
YYHHH
YHHXB
BBHBB
BBBBB
这四个地方就是暖流的边界。
只有周围的四个格子是蓝蓝的大海或者石头和沙滩,才可能是暖流的边界。
我们可以把这些边界放进一个队列里,然后把图上变成大海。
YYYBB
YYHHB
YBHXB
BBBBB
BBBBB
然后就有了新的边界。
如此反复,最后剩下的暖流就是爱花的位置。
YYYBB
YYHBB
YBBXB
BBBBB
BBBBB
原来找到爱花这么容易。
时间复杂度O(N^2)
空间复杂度O(N^2)
恩,如果大海的结构这么简单的话,的确如此。

又看了半天,不得不佩服大海的深邃。
YYYHB
YYHHH
YHHXB
YXHXB
YYYYY
我们用之前的方法
YYYHB
YYHHH
YHHXB
YXHXB
YYYYY
放进队列,然后把它们变成大海
YYYBB
YYHHB
YHHXB
YXHXB
YYYYY

YYYBB
YYBBB
YHBXB
YXHXB
YYYYY
然后就成了这样,有两个位置看起来像是爱花所在的地方。
但事实并非如此。
YYYHB
YYHHH
YHHXB
YXHXB
YYYYY
爱花其实在这里。

Solution2

又想了半天。
看起来可以DP。
Flow[TIME][X][Y]表示暖流的初始位置是(X,Y),经过时间TIME以后,形成的图案会不会和海流图不相符(不应是H的地方出现了H则不相符,应出现H的地方没有出现H认为相符)

YYYHB
YYHHH
YHHXB
BBHBB
BBBBB
海流图
YYYBB
YYHHB
YBHXB
BBBBB
BBBBB
相符的图(蓝色部分应该出现H但没有出现)
YYYHH
YYHHH
YHHXH
BHHHB
BBHBB
不相符的图(红色部分不该出现H但出现了)
F[TIME][X][Y]=F[TIME-1][X-1][Y]&&F[TIME-1][X][Y-1]&&F[TIME-1][X+1][Y]&&F[TIME-1][X][Y+1]
记忆化DP 时间复杂度O(N^3) 空间复杂度 O(N^3)
找到最大的TIME,对应的X和Y就是爱花的位置。
因为光相信自己一定能找到爱花,所以爱花的位置确定(不会有两个位置满足条件)。

Solution3
更好的算法?
还得继续想吧。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;

const int N = 305;

char map[N][N];
bool f[N<<1][N][N][2];//f[T][x][y]表示设x,y是张ansT     即牺 
char ss[N];
int n,m;

bool check(int T, int x, int y){
    if( f[T][x][y][0] ) return f[T][x][y][1];
    if(x==0 || y==0 || x==n+1 || y==m+1) return true;
    if(map[x][y] != 'H') return true;
    f[T][x][y][0] = true;
    if(T == 0) return f[T][x][y][1] = true;
    if(map[x-1][y]=='B' || map[x+1][y]=='B' || map[x][y-1]=='B' || map[x][y+1]=='B')
        return f[T][x][y][1] = false;
    f[T][x][y][1] = check(T-1,x-1,y) && check(T-1,x+1,y) && check(T-1,x,y-1) && check(T-1,x,y+1);
    return f[T][x][y][1];
}

int main(){
    freopen ("calm.in", "r", stdin);
    freopen ("calm.out", "w", stdout);
    scanf("%d%d", &n, &m);
    for(register int i=1; i<=n; i++){
        scanf("%s", ss);
        for(register int j=1; j<=m; j++)
            map[i][j] = ss[j-1];
    }
    for(register int t=n+m; t>=1; t--)
        for(register int i=1; i<=n; i++)
            for(register int j=1; j<=m; j++){
                if(map[i][j] == 'H') check(t, i, j);
                if( f[t][i][j][1] ){
                    printf("%d %d", i, j);
                    return 0;
                }
            }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值