標籤:pre 碰撞 blank href targe track back post 輸入
id=3009">連結:poj 3009
題意:在一個冰面網格板上,有空白處(無障礙),和障礙塊。有一個小石頭,給定其起點和終點。求從起點到終點的最小步數
規則:小石頭不能在障礙區運動,一旦從某一方向開始運動,不會改變方向,也不會停止。除非碰到障礙物或到達終點才會停止,這為一步。若碰到障礙物。小石頭將停在障礙物的旁邊,被碰到的一個障礙物將消失。
輸入:1代表障礙物(不可到達),0代表空白區,2,代表起點。3代表終點
輸出:若小石頭能到達終點,且步數最多為十步,輸出最小步數,否則輸出-1.
思路:dfs+回溯
要確定小石頭是運動還是精巧狀態,若為精巧,旁邊為障礙區。是不能走的。而且當開始小石頭運動,到接下來第一次停止為一步,期間方向沒改變。僅僅有停止後才幹改變運動方向,因此dfs時要確定小石頭的運動狀態和方向.
剪枝:由於步數不能超過10,能夠以此作為剪枝條件
#include<stdio.h>int m,n,a[21][21],min;int x[4]={-1,1,0,0},y[4]={0,0,-1,1};void dfs(int i,int j,int step,int dir,int sta,int flag) { //step表示當前步數,dir運動方向。sta運動狀態,flag是否消除障礙 int k,r,c; if(step>10) //剪枝,步數不能超過10 return ; if(a[i][j]==3){ //到達終點,若步數比最小步數小,更新最小步數 if(step<min) min=step; return ; } if(flag){ // flag為1時,消除小石頭碰撞的一個障礙塊 r=i+x[dir]; c=j+y[dir]; a[r][c]=0; } if(!sta){ //精巧時 for(k=0;k<4;k++){ r=i+x[k]; c=j+y[k]; if(r>=1&&r<=n&&c>=1&&c<=m&&a[r][c]!=1) //推斷邊界 dfs(r,c,step+1,k,1,0); } } else{ //運動時 方向不變 r=i+x[dir]; c=j+y[dir]; if(r>=1&&r<=n&&c>=1&&c<=m){ //推斷邊界 if(a[r][c]!=1) dfs(r,c,step,dir,1,0); else //當碰到障礙物。停止運動。狀態sta變為0,下一步要消除障礙。變為1 dfs(i,j,step,dir,0,1); } else //若下一步超出邊界,則不能再繼續運動 return ; } if(flag){ r=i+x[dir]; c=j+y[dir]; a[r][c]=1; } return ;}int main(){ int i,j,r,c; while(scanf("%d%d",&m,&n)!=EOF){ if(m==0&&n==0) break; for(i=1;i<=n;i++) for(j=1;j<=m;j++){ scanf("%d",&a[i][j]); if(a[i][j]==2){ //找到起點 r=i; c=j; } } min=11; //由於最小步數不可能超過10,可將其初始化為11 dfs(r,c,0,0,0,0); if(min==11) min=-1; printf("%d\n",min); } return 0;}
poj 3009 Curling 2.0 (dfs)