zoukankan      html  css  js  c++  java
  • 洛谷P1363花里胡哨写法

    #include<stdio.h>
    #include<string.h>
    #include<queue>
    using namespace std;
    #define abss(i) -(i)
    #define check(a) ((a) == 'S' || (a) == '.')
    #define checkj (j[0] || j[1])
    
    queue <int> que;
    struct node
    {
        int rt, to;//list
    }lst[6060],arc[50];//POS
    int head[6060];//no-cross ADT adt NB
    
    char s[1505][1505];
    int vis[6006],vis1[5];
    int n, m, st, cnt;
    int dx[4] = {0,0,1,-1};
    int dy[4] = {1,-1,0,0};
    int j[2];
    int vis2[60006];
    
    int check1(int x, int y)
    {
        if((x == 1 || x == n) && (y == 1 || y == m))
        {
            int pos = ((x==1?0:1)<<1) | (y==1?0:1);
            int flag = 0;
            for(int i = 0; i < 4; i++)
                if(i != pos && (i^pos) != 3)
            {
                int ey = (i&1)?m:1, ex = (i&(2))?n:1;
                flag |= (s[ex][ey] != '#');
            }
            return flag;
        }
        return 0;
    }
    
    int check2(int x, int y)
    {
        if(x == n || x == 1 || y == m || y == 1 )
        {
            int ex = x, ey = y;
            if(ex == 1 || ex == n) ex = ex==1?n:1;
            else if(ey == 1 || ey == m) ey = ey==1?m:1;
            return s[ex][ey] != '#';
        }
        return 0;
    }
    
    void build_poi(int x, int y, int rt)//dfs 扫图建点 设置连通块的边(建的点与对应点即为一条边)
    {
        int pos ;
        //add point
        if(check1(x, y))
        {
            //link
            pos = (((x==1?0:1)<<1) + (y==1?0:1));
            arc[pos].to = head[rt];
            head[rt] = abss(pos) - 1;//hash
            arc[pos].rt = rt;
        }
        else if(check2(x, y))
        {
            if(x > 1 && x < n) pos = (x-1) + (y==1?0:(n-2));
            else pos = (y-1) + (x==1?0:(m-2)) + n*2-4;
            lst[pos].to = head[rt];
            head[rt] = pos;
            lst[pos].rt = rt;
        }
        if(s[x][y] == 'S') {st = rt;}
        s[x][y] = 'B';
        for(int i = 0; i < 4; i++)
        {
            int ex = x + dx[i], ey = y + dy[i];
            if(check(s[ex][ey])) build_poi(ex, ey, rt);
        }
    }
    
    int jmp(int a)// 该函数等价于 v = e[pos].v
    {
        if(a <= n-2) return a+n-2;
        if(a <= 2*n-4) return a-n+2;
        if(a <= 2*n-4+m-2) return a+m-2;
        return a-m+2;
    }
    
    void jmp1(int now, int i, int dt)//追踪当前dfs跳了哪些边
    {
        if(now < 0)
        {
            now = abss(now+1);
            if(now - i == -1) j[0] += dt;
            else if(now - i == 1) j[0] -= dt;
            else if(now - i == 2) j[1] -= dt;
            else if(now - i == -2) j[1] += dt;
            return ;
        }
        if(now <= n - 2) j[0] += dt;
        else if(now <= n*2 - 4) j[0] -= dt;
        else if(now <= n*2 - 4 + m-2) j[1] += dt;
        else j[1] -= dt;
    }
    
    int findd(int pos, int rt)
    {
        if(!vis2[rt]) {vis2[rt] = 1;que.push(rt);}//设置vis2,及时入队
        vis[rt] = 1;
        if(rt == st) return 1;//同第一行,及时处理
        int now = head[rt];
        while(now)
        {
            if(now > 0)
            {
                int tar = jmp(now);//跳边
                rt = lst[tar].rt;
                jmp1(now, 0, 1);
                if(!vis[rt] && !vis2[rt]) {vis2[rt] = 1;que.push(rt);}
                if(tar != pos && !vis[rt] && findd(pos, rt)) return 1;
                if(rt == st && tar != pos && checkj) return 1;
                jmp1(now ,0, -1);
            }
            else
            {
                for(int i = 0; i < 4; i++)
                {
                    if(((abss(now+1))^i) != 3 && arc[i].rt && abss(i)-1 != pos )
                    {
                        jmp1(now, i, 1);
                        if(!vis2[arc[i].rt] && !vis[arc[i].rt]) {vis2[arc[i].rt] = 1;que.push(arc[i].rt);}
                        if(!vis[arc[i].rt] && findd(pos,arc[i].rt)) return 1;
                        if(arc[i].rt == st && checkj) return 1;
                        jmp1(now, i, -1);
                    }
                }
            }
            now = now>0?lst[now].to:arc[abss(now+1)].to;
        }
        return 0;
    }
    
    /*
    该题需要测试 s点能访问到的的所有连通块能否访问自身
    
    */
    int dfs()
    {
        for(int i = 1; i <= cnt; i++) vis2[i] = 0;
        while(!que.empty())
        {
            int pos = head[que.front()];
            st = que.front();
            que.pop();
            while(pos)
            {
                j[0] = j[1] = 0;
                for(int i = 0; i <= (m+n)<<1; i++) vis[i] = 0;
                for(int i = 0; i < 5; i++) vis1[i] = 0;
                vis[st] = 1;
                if(pos > 0)
                {
                    jmp1(pos,0,1);
                    if(findd(pos, lst[jmp(pos)].rt)) return 1;
                    jmp1(pos,0,-1);
                }
                else
                {
                    for(int i = 0; i < 4; i++)
                    {
                        if(i != abss(pos+1) && (i^(abss(pos+1)) != 3) && arc[i].rt)
                        {
                            jmp1(pos,i,1);
                            if(findd(pos, arc[i].rt)) return 1;
                            jmp1(pos,i,-1);
                        }
                    }
                }
                pos = pos>0?lst[pos].to:arc[abss(pos+1)].to;
            }
        }
        return 0;
    }
    
    int main()
    {
        for(int i = 1; i <= 1501; i++) s[0][i] = s[i][0] = '#';
        while(~scanf("%d%d",&n,&m))
        {
            for(int i = 1; i <= n; i++) scanf("%s",s[i]+1);if(m + n <= 3) {puts("Yes");continue;}
            for(int i = 1; i <= n; i++) s[i][m+1] = '#';
            for(int i = 1; i <= m; i++) s[n+1][i] = '#';
            st = cnt = 0;
            //build point //存在对点的点 记录至head
            for(int i = 1; i <= n; i++) {if(check(s[i][1])) build_poi(i, 1, ++cnt);if(check(s[i][m])) build_poi(i, m, ++cnt);}
            for(int i = 1; i <= m; i++) {if(check(s[1][i])) build_poi(1, i, ++cnt);if(check(s[n][i])) build_poi(n, i, ++cnt);}
            while(!que.empty()) que.pop();
            que.push(st);
            if(st && dfs()) puts("Yes");//
            else puts("No");
            for(int i = 1; i <= cnt; i++) head[i] = 0;
            for(int i = 0; i < 5; i++) arc[i].rt = arc[i].to = 0;
        }
        return 0;
    }
    /*
    将二维的图压成一维
    此题只有能跳边的点才可能有效,在遍历的时候只需要考虑边界上&&能跳边的点。
    不同的连通块之间用边界上的点连接(只有这一种方式)
    #..##
    ##S##
    #####
    .....
    #.###
    只有(1,2)(5,2) 和 (4,1)(4,5)两个点值得记录,因为它们能通向别的区域,并且存在绕回来的可能性。
    使用hash映射,将二维的点压成1维。
    
    -0 07 08 09 10 -1
    01             04
    02             05
    03             06
    -2 11 12 13 14 -3
    
    左右边上的点满足 (y==1||y==m)&&(1<x<n) 左: x <= n-2 , 右: x <= 2*(n-2) 
    左右跳边用n-2。 opp = now + n-2 || now - n-2
    判断左右关联需要在明确范围后 a == b + n-2 || a == b - (n-2)
    上下边同理
    跳边用 m-2。
    左右边的点二维映射到一维的方式 pos = x-1 + y==1?0:(n-2)
    上下                           pos = y-1 + x==1?0:(m-2) + 2*(n-2)
    
    四角的点由于和左右上下都可能相连,不能普通处理。
    pos = x==1?0:1<<1 + y==1?0:1  分别为 00 01 10 11 首位决定横坐标为1还是n,末位决定纵坐标为1还是m
    注,在图中的坐标系为
    O y-->
    x
    |
    v
    将其整体逆时针旋转90°即可恢复为常见的坐标系。
    
    为了区分,将四角的点映射为负值 -1 -2 -3 -4
    pos = abss(now) - 1;
    还原用 now = abss(pos+1);
    
    可能跳的边为
    for(int i = 0; i < 3; i++) 
    {
        (i != pos && (i^(abss(pos+1))!=3));
    }
    满足条件的 i 和 pos 能跳
    
    */
    洛谷P1363

    此写法虽然代码量大,运行时间长,但是可以用来演队友。

     1 #include<stdio.h>
     2 
     3 char s[1505][1505];
     4 int vx[1505][1505],vy[1505][1505];
     5 int n, m;
     6 int dx[4] = {0,0,1,-1};
     7 int dy[4] = {1,-1,0,0};
     8 const int inf = 0X3F3F3F3F;
     9 
    10 int dfs(int sx, int sy)
    11 {
    12     int x = (sx%n+n)%n, y = (sy%m+m)%m;
    13     if(s[x][y] == '#') return 0;
    14     if(vx[x][y] != inf) return (sx != vx[x][y] || sy != vy[x][y]);
    15     vx[x][y] = sx, vy[x][y] = sy;
    16     for(int i = 0; i < 4; i++)
    17         if(dfs(sx+dx[i],sy+dy[i])) return 1;
    18     return 0;
    19 }
    20 
    21 int main()
    22 {
    23     while(~scanf("%d%d",&n,&m))
    24     {
    25         for(int i = 0; i < n; i++) scanf("%s",s[i]);
    26         for(int i = 0; i < n; i++) for(int j = 0; j < m; j++) vx[i][j] = vy[i][j] = inf;
    27         for(int i = 0; i < n; i++)
    28         {
    29             for(int j = 0; j < m; j++)
    30             {
    31                 if(s[i][j] == 'S')
    32                 {
    33                     if(dfs(i,j)) printf("Yes
    ");
    34                     else puts("No");
    35                     break;
    36                 }
    37             }
    38         }
    39 
    40     }
    41     return 0;
    42 }
    正常写法

    记录第一次到达某点的坐标,以后遍历和第一次对比。

    注意要沿着原路径走,否则都是yes。

  • 相关阅读:
    nsq main里面golang多个协程管理写法
    关于centos压测的问题
    Jaeger全链路go实现,包含http和消息队列的链式传递
    mstsc远程报:这可能是由于CredSSP 加密Oracle修正的两种完美解决方法
    Axure9:一键复制Iconfont图标到Axure的插件安装
    Axure9:导入阿里云DataV.GeoAtlas矢量地图到Axure
    Axure:编辑技巧:拖动复制、编组、组内选中、穿透选中、选中模式
    Axure学习一:打开软件,预览和生成HTML原型、安装Chrome插件
    Axure RP授权码
    vm 安装rethat和centos
  • 原文地址:https://www.cnblogs.com/zhonghuizaijian/p/13337384.html
Copyright © 2011-2022 走看看