您的位置:首页 > 其它

搜索DFS+BFS和剪枝问题

2015-08-02 17:53 459 查看
HUD 1010

题意:输入一个n*m的迷宫,和一个T:可以在迷宫中生存的最大时间。S为起点,D为终点。并且,每个格子只能踩一次,且只能维持一秒,然后该块地板就会塌陷。所以你必须每秒走一步,且到D点时,所用时间为T。用深搜。

之前,误以为就是找到最短路,结果不是,而是恰好T秒走出迷宫。用DFS,超时可见剪枝的重要。

这题的剪枝主要是两个方面。

1:利用曼哈顿距离剪枝 —– 算出终点到该点的距离,与剩余的时间进行比较,如果到终点的距离大于剩余的时间,很明显是不能到达的。

2:利用奇偶剪枝 —- 如果二者之间距离与剩余时间的差是奇数,那么就舍掉,因为当二者的差值是0时可以刚好到达,当二者的差值大于0时,就必须绕个远路拐两个直角到达,而此时必须是偶数。

[code]#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <math.h>
using namespace std;
int n,m,T;
const int N = 10;
char Map

;
bool vis

;
bool ans;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
int edx,edy;
void DFS(int x,int y,int t)
{
    if(x==edx && y==edy && t==T) {ans=true;return;}
    if(t>=T) return;
    if(x==edx && y==edy) return;
    int dis=T-(fabs(edx-x)+fabs(edy-y)+t);//剪枝处
        if(dis<0 ||dis%2 ) return;

    for(int i=0;i<4;i++)
    {
        int xx=x+dir[i][0];
        int yy=y+dir[i][1];
        if(xx<1||xx>n) continue;
        if(yy<1||yy>m) continue;
        if(Map[xx][yy]=='X' ||!vis[xx][yy]) continue;
        vis[xx][yy]=false;
        DFS(xx,yy,t+1);
        if(ans) return;
        vis[xx][yy]=true;
    }
    return;
}
int main()
{
    while((scanf("%d %d %d",&n,&m,&T))!=EOF)
    {
        if(n==0 &&m==0 && T==0) break;
        int x,y;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf(" %c",&Map[i][j]);
            if(Map[i][j]=='S')
                x=i,y=j;
            if(Map[i][j]=='D')
                edx=i,edy=j;
        }
        ans=false;
        memset(vis,true,sizeof(vis));
        vis[x][y]=false;
        DFS(x,y,0);
        if(ans) printf("YES\n");
        else printf("NO\n"); 
    }
    return 0;
}


HDU 1175

题意就是我们平时玩连连看的意思,然后只能转两个弯,不能从外围走。

然后用DFS很残酷的TLE了。后来才想到一个剪枝点。

剪枝处:用vis的二维数组来存储当前的转弯数的情况,当前(i,j)这个点的转弯数大于vis[i][j]的时候,我们就return,因为vis

存储的是全局的最优解,这真是个大大的剪枝处。将标记数组的功能用的淋漓尽致,以后要记着点。


ps:剪枝来源:/article/1439542.html

[code]#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1000+10;
int Map

;
int vis

;
int n,m,edx,edy;
bool flag;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
void dfs(int x,int y,int cnt,int aim)
{
    if(flag) return;
    if(x<1||y<1||x>n||y>m||cnt>2) return; 
    if(x==edx && y==edy && cnt<=2) {flag=true;return;}
    if(Map[x][y]!=0) return;
    if(vis[x][y]!=-1&&vis[x][y]<=cnt) return;//剪枝处
    vis[x][y]=cnt;
    for(int i=0;i<4;i++)
    {
        int xx=x+dir[i][0];
        int yy=y+dir[i][1];
        if(i==aim) dfs(xx,yy,cnt,i);
        else dfs(xx,yy,cnt+1,i);
    }
}
int main()
{
    //freopen("test.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(~scanf("%d %d",&n,&m))
    {
        if(n==0 &&m==0) break;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&Map[i][j]);
        int Q;
        scanf("%d",&Q);
        while(Q--)
        {
            int x,y;
            flag=false;
            scanf("%d %d %d %d",&x,&y,&edx,&edy);
            if(x<1||x>n||y<1||y>m||edx<1||edx>n||edy<1||edy>m||(x==edx&&y==edy)) {printf("NO\n");continue;}
            if(Map[x][y]!=Map[edx][edy]||Map[x][y]==0 ||Map[edx][edy]==0)  {printf("NO\n");continue;}
            memset(vis,-1,sizeof(vis));
            vis[x][y]=0;
            for(int i=0;i<4;i++)
            {
                int xx=x+dir[i][0];
                int yy=y+dir[i][1];
                dfs(xx,yy,0,i);
                if(flag) break;
            }
            if(flag) printf("YES\n");
            else printf("NO\n");
        }
    }
    return 0;
}


未完待续 :)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: