zoukankan      html  css  js  c++  java
  • P1363 幻象迷宫

    题意:给你一个nxm的迷宫g(x,y范围是0~n - 1和0~m - 1),‘#’不能走,‘.’可以走,'S'作为起点,现在将迷宫扩展成无穷大,扩展方法是:任意一个(x, y)位置的字符c = g(x % n, y % m),现在问你可不可以从起点处走到无穷远处。

    例子:

    原始迷宫5x5为中间的黄色区域,标红色的位置的坐标为(-2, -4), 而 (-2) % 5 = 3, (-4) % 5 = 1, 所以(-2, 4)位置处,应该和g(3, 1)相同,所以为S。

    思路:对于一个位置A(x, y)如果能够走到另一个位置B(p, q), A≠B,并满足A和B在对应的nxm图中的相对位置相同(意思是:p % n = x % n, q % m = y % m),那么不断重复这个过程,就一定能走到无穷远处。所以考虑从起点(位于原图中,扩展的图中的其他S看成是‘.’)开始dfs(此处是flood fill),一旦两次都遍历到了原图上的同一位置,并且这两次遍历到的点不同,那么说明可以走到无穷远处,否则不能。

    注意红色部分:假设两次遍历到的点为(x,y)和(p,q), 那么遍历到原图上的同一位置指的是p % n = x % n, q % m = y % m(是就相对位置而言的)

    一开始我是每遍历到一个点(x, y)就对原图上的(x % n, y % m)标记访问过,然后在后面的遍历过程中一旦发现一个位置(p, q)有(p % n, q % m)已经被访问过,那么就认为能够走到无穷远,这是错的,因为有可能(x, y)和(p, q)是同一个点。

    由于模运算的不可逆,意思就是说,如果只是简单的在访问到(x,y)时,对(x % n,y % m)标记已访问,那么在下一次搜索到某点(p, q)时就算(p % n,q % m)恰好为(x, y)标记过的地方,也不能肯定(p, q)和(x, y)不是同一点,所以有必要对于原图中的每一个位置(u, v)保存一下第一次访问到它(指x % n = u, y % m = v)的坐标(x, y)

    由于涉及到负数取模,所以还得自己写一下取模函数。

    #include<iostream>
    #include<cstring>
    
    using namespace std;
    
    const int N = 1510;
    
    int n, m;
    char g[N][N];
    int st[N][N][3]; // st[u][v][0~2]分别表示:是否访问过,x和y
    int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
    
    int mod(int a, int b){
        if(a >= 0) return a % b;
        return ((-a / b + 1) * b + a) % b;
    }
    
    int dfs(int x, int y){
        
        for(int i = 0; i < 4; i ++){
            int a = x + dx[i], b = y + dy[i];
            int ma = mod(a, n), mb = mod(b, m);
            
            if(g[ma][mb] == '#') continue;
            if(st[ma][mb][0]){
                if(st[ma][mb][1] != a || st[ma][mb][2] != b) return 1;
                continue;
            }
            
            st[ma][mb][0] = 1, st[ma][mb][1] = a, st[ma][mb][2] = b;
            if(dfs(a, b)) return 1;
        }
        
        return 0;
    }
    
    int main(){
        while(cin >> n >> m){
            memset(st, 0, sizeof st);
            
            int x, y;
            for(int i = 0; i < n; i ++)
                for(int j = 0; j < m; j ++){
                    cin >> g[i][j];
                    if(g[i][j] == 'S') x = i, y = j;
                }
            
            st[x][y][0] = 1, st[x][y][1] = x, st[x][y][2] = y;
            
            if(dfs(x, y)) cout << "Yes" << endl;
            else cout << "No" << endl;
        }
        
        return 0;
    }
    
  • 相关阅读:
    线程池优化之充分利用线程池资源
    Spring异步调用原理及SpringAop拦截器链原理
    使用pdfBox实现pdf转图片,解决中文方块乱码等问题
    Spring BPP中优雅的创建动态代理Bean
    转载:ThreadPoolExecutor 源码阅读
    Springboot定时任务原理及如何动态创建定时任务
    SpringSecurity整合JWT
    SpringMvc接口中转设计(策略+模板方法)
    HashMap 源码阅读
    支付宝敏感信息解密
  • 原文地址:https://www.cnblogs.com/tomori/p/14320956.html
Copyright © 2011-2022 走看看