hdu

这道题因为某些位置要重复走,所以不能用标记的方法,但是为了提高效率,可以采用time[]数组和step[]数组来剪枝,很容易想到,当你从一条路劲走到(x,y)处的时间和步骤

比从另一条路劲走到(x,y)处的时间和步骤小时,那么time[]数组和step[]数组将这个最小的时间和步骤记录下来,即time[]和step[]记录的是到达每个位置用的最小的时间和步骤,如果当你从某一条路径到达(x,y)处的时间和步骤大于已记录值时,直接返回而不继续走下去。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>


const int MAX = 9;

int dir[4][2]={1,0,-1,0,0,1,0,-1};

int map[MAX][MAX],step[MAX][MAX],time[MAX][MAX];
int n,m,sx,sy,dx,dy,minx;

void dfs(int x,int y,int len,int cnt){
    if(x<0 || y<0 || x>=n || y>=m)return;
    if(len<=0 || cnt>=minx)return;
    if(map[x][y]==0)return;
    if(map[x][y]==3){
        if(cnt<minx)minx=cnt;
        return;
    }
    if(map[x][y]==4){
        len=6;
    }
    //下面的这个剪枝很重要,不剪就会超时
    //从当前点x,y走到下一个可能点的距离大于从其他途径到tx,ty的距离,且到tx,ty点时的剩余时间大于由x,y点到tx,ty点后的剩余时间,就跳过
    //这是因为结点可重复访问所以本身没标记,那么当上述条件满足时,由tx,ty开始的最优解已经求过(存在或者不存在),所以不需要再重复求了。
    if(cnt>=step[x][y] && time[x][y]>=len)return;
    step[x][y]=cnt;
    time[x][y]=len;
    int tx,ty,i;
    for(i=0;i<4;++i){
        tx = x+dir[i][0];
        ty = y+dir[i][1];
        dfs(tx,ty,len-1,cnt+1);
    }
}

int main(){

    //freopen("in.txt","r",stdin);
    int t,i,j,len,cnt;
    scanf("%d",&t);
    while(t--){
        scanf("%d %d",&n,&m);
        for(i=0;i<n;++i){
            for(j=0;j<m;++j){
                time[i][j]=0;
                step[i][j]=INT_MAX-3;//这里置一个大数,表示到i,j的步数无限大
                scanf("%d",&map[i][j]);
                if(map[i][j]==2){
                    sx = i;
                    sy = j;
                }else if(map[i][j]==3){
                    dx = i;
                    dy = j;
                }
            }
        }
        len = 6;
        cnt = 0;
        minx = INT_MAX;
        dfs(sx,sy,len,cnt);
        if(minx==INT_MAX){
            printf("-1
");
        }else{
            printf("%d
",minx);
        }
    }

    return 0;
}
View Code
原文地址:https://www.cnblogs.com/acm-jing/p/4369978.html