• [HDU] 1175 连连看 剪枝优化后的性能飙升


    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=1175

    方法:在每一步都要维护4个信息,当前坐标,当前方向(垂直还是水平),当前已经折了多少次和携带的目标数字。根据这几个信息,在一步深搜索探寻下一步的时候,选择下一步的标准是:

    没有访问过 && (是可以走的路 || (不是路而是一个和目标数字相等的数 && 该位置就是目标位置))。

    整个算法的过程是:

    1.获取输入后验证是否可达,标准为:

      a.两个位子的数字必须相同。

      b.两个位子的数字必须不能有0。

      c.目标位置的直接周边4个必须至少有一个0.

    如果三个条件不能都满足,直接输出NO。

    2.上述条件都满足,可以开始深搜,首先要初始化。这里重点要设置以下4个数据:

      a.可以 走纯水平路线到达目标的最左边的位子的列:pfromLeft

      b.可以 走纯水平路线到达目标的最左边的位子的列:pfromRight

      c.可以 走纯垂直路线到达目标的最上边的位子的列:pfromUp

      d.可以 走纯垂直路线到达目标的最下边的位子的列:pfromDown

    3.正式开始深搜。深搜过程中不断设置每一步上是当时维持的方向,再和上一步的方向比较得到当前改变方向的次数,也就是经过的折线个数。当折线个数超过2,则不从该位子进行深搜。而当折线个数不超过2刚好等于2的时候,重点剪枝就在这里:

      a.如果当前的方向是水平的,但是目标位子在水平方向不可达,剪掉。

      b.如果当前的方向是水平的,且目标位子在水平方向可达,但是当前位置和目标位置不在同一行,剪掉。

      c.如果当前的方向是水平的,且目标位子在水平方向可达,且当前位置和目标位置在同一行,但当前位置不在pfromLeft 和 pfromRight的比区间内,剪掉。

      

      d.如果当前的方向是水平的,且目标位子在水平方向可达,且当前位置和目标位置在同一行,且当前位置在pfromLeft 和 pfromRight的比区间内,搜索成功,直接返回成功,搜索结束。

      e.如果当前的方向是垂直的,但是目标位子在垂直方向不可达,剪掉。

      f.如果当前的方向是垂直的,且目标位子在垂直方向可达,但是当前位置和目标位置不在同一列,剪掉。

      g.如果当前的方向是垂直的,且目标位子在垂直方向可达,且当前位置和目标位置在同一列,但当前位置不在pfromLeft 和 pfromRight的比区间内,剪掉。

      

      h.如果当前的方向是垂直的,且目标位子在垂直方向可达,且当前位置和目标位置在同一列,且当前位置在pfromUp和 pfromDown的比区间内,搜索成功,直接返回成功,搜索结束。

    感想:深感剪枝的重要性,不剪的话,题目给的10秒时间都要超时,剪了的话只要62ms.

    代码:

    View Code
    #include <iostream>
    #include <queue>
    using namespace std;
    int n,m;
    int map[1002][1002];
    bool visited[1002][1002];
    int deriction[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
    int g_edx,g_edy;
    bool fromUp,fromDown,fromLeft,fromRight;
    int pfromUp,pfromDown,pfromLeft,pfromRight;
    struct step
    {
        int x;
        int y;
        int currentChangeDirection;
        bool isVertival;
        int carry;
    };
    bool canGo(step cur,int x,int y)
    {
        return !visited[x][y] && (map[x][y]==0|| (map[x][y] == cur.carry && x ==g_edx && y ==g_edy));
    }
    bool DFSSearch(step st,step ed)
    {
        int n_x,n_y;
        if(st.x == ed.x && st.y==ed.y)
            return true;
        visited[st.x][st.y]=true;
        for(int i=0;i<4;i++) //vertical  true
        {
            n_x = st.x+deriction[i][0];
            n_y = st.y+deriction[i][1];
            if(canGo(st,n_x,n_y))
            {
                 step n_step;
                 n_step.x = n_x;
                 n_step.y = n_y;
                 n_step.isVertival = i%2==0;
                 n_step.carry = st.carry;
                 if(st.currentChangeDirection ==-1)
                     n_step.currentChangeDirection=0;
                 else if(st.isVertival!=n_step.isVertival)
                     n_step.currentChangeDirection = st.currentChangeDirection+1;
                 else
                     n_step.currentChangeDirection = st.currentChangeDirection;
                 if(n_step.currentChangeDirection<=2)
                 {
                     if(n_step.currentChangeDirection==2)
                     {
                         if(n_step.isVertival && (fromDown || fromUp) && n_step.y == g_edy)
                         {
                             if(n_step.x>=pfromUp && n_step.x<=pfromDown)
                                 return true;
                         }
                         if(!n_step.isVertival && (fromLeft || fromRight) && n_step.x== g_edx)
                         {
                             if(n_step.y>=pfromLeft && n_step.y<=pfromRight)
                                 return true;
                         }
                     }
                     else if(DFSSearch(n_step,ed))
                        return true;
                 }
            }
        }
        visited[st.x][st.y]=false;
        return false;
    }
     
    bool search(int stx, int sty,int edx,int edy)
    {
        step st_step,ed_step;
        st_step.x =stx;
        st_step.y = sty;
        ed_step.x =edx;
        ed_step.y =edy;
        g_edx = edx;
        g_edy = edy;
        st_step.currentChangeDirection=-1;
        st_step.carry = map[stx][sty];
        int t_edx=edx,t_edy = edy;
        while(map[t_edx+1][t_edy]==0)
                t_edx++;
        pfromDown = t_edx;
        t_edx=edx,t_edy = edy;
        while(map[t_edx][t_edy+1]==0)
                t_edy++;
        pfromRight = t_edy;
        t_edx=edx,t_edy = edy;
        while(map[t_edx][t_edy-1]==0)
                t_edy--;
        pfromLeft = t_edy;
        t_edx=edx,t_edy = edy;
        while(map[t_edx-1][t_edy]==0)
                t_edx--;
        pfromUp = t_edx;
        return DFSSearch(st_step,ed_step);
    }
     
    bool validate(int stx, int sty,int edx,int edy)
    {
        if(map[stx][sty] != map[edx][edy])
            return false;
        if(map[stx][sty] ==0 || map[edx][edy]==0)
            return false;
        if(map[stx-1][sty] ==0)
            fromUp =true;
        if(map[stx][sty-1]==0)
            fromLeft = true;
        if( map[stx][sty+1]==0)
            fromRight = true;
        if(map[stx+1][sty]==0)
            fromDown = true;
        if(!fromUp && !fromLeft && !fromRight && !fromDown)
            return false;
        return true;
    }
    void main()
    {
        int tc;
        while(scanf("%d %d",&n,&m) && n+m!=0)
        {
           memset(map,-1,sizeof(map));
           
           for(int i =1;i<=n;i++)
               for(int j=1;j<=m;j++)
                   scanf("%d",&map[i][j]);
            scanf("%d",&tc);
            int stx,  sty, edx, edy;
            for(int i =0;i<tc;i++)
            {
                 memset(visited,false,sizeof(visited));
                scanf("%d %d %d %d",&stx,&sty,&edx,&edy);
                if(!validate(stx,  sty, edx, edy))
                    cout<<"NO"<<endl;
                else
                {
                    if(search(stx,  sty, edx, edy))
                        cout<<"YES"<<endl;
                    else
                        cout<<"NO"<<endl;
    
                }
            }
    
        }
    }
  • 相关阅读:
    列举进程
    数据输出十六进制格式
    double精确度。。。。。
    ip查询详细地址
    通过up2date进行系统升级
    linux系统,安装DVD中所有RPMs包的方法
    修改服务状态
    /etc/sysctl.conf文件
    希望
    RHEL3.9GA virtio 设定方法
  • 原文地址:https://www.cnblogs.com/kbyd/p/3028353.html
Copyright © 2020-2023  润新知