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\n"); }else{ printf("%d\n",minx); } } return 0; }