[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;

            }
        }

    }
}
原文地址:https://www.cnblogs.com/kbyd/p/3028353.html