poj3009(转载,写的比自己的好太多,直接转来了)

来源:互联网 发布:无root修改手机mac地址 编辑:程序博客网 时间:2024/06/09 17:48

原文地址:http://blog.csdn.net/tsaid/article/details/6759905

一直想用bfs写的但是由于不会写递归的bfs而且阻挡物被碰后将消失。所以还是回溯比较好。

就是要求把一个冰壶从起点“2”用最少的步数移动到终点“3”

其中0为移动区域,1为石头区域,冰壶一旦想着某个方向运动就不会停止,也不会改变方向(想想冰壶在冰上滑动),除非冰壶撞到石头1 或者 到达终点 3

 

注意的是:

冰壶撞到石头后,冰壶会停在石头前面,此时(静止状态)才允许改变冰壶的运动方向,而该块石头会破裂,石头所在的区域由1变为0. 也就是说,冰壶撞到石头后,并不会取代石头的位置。

终点是一个摩擦力很大的区域,冰壶若到达终点3,就会停止在终点的位置不再移动。

 

解题思路:

要先明确:

0为滑动区域

1为石头区域

2为起点,也是可滑动区域

3为终点,不可滑动区域

(1) 起点为“2”,也是一个可滑动的区域,所以标记起点位置之后,可以把起点当做0

(2) 注意区分冰壶是运动的还是静止的,若是静止的话,旁边1格有石头是不能走的。

(3) 输出冰壶从2到3的最短路,如果最短路的步数大于10(不包括10),视作无法走到终点(其实这是用来剪枝的)

(4) 滑动过程中冰壶不允许出界

 基于上面的原则,不难发现:

(1)所谓的“走一步”,就是指冰壶从一个静止状态到下一个静止状态,就是说冰壶在运动时经过的“格数”不视作“步数”,也就是说冰壶每次移动的距离都是不定的。

(2)还有就是由于石头会因为冰壶的碰撞而消失,因此冰壶每“走一步”,场地的环境就会改变一次。

(3)基于(2),可以发现本题虽然是要找 “最短路”,但是BFS几乎不可能,因为每“走一步”,场地的状态就要改变一次;而如果该步不满足要求,又要求把场地的状态还原到前一步,这只有DFS能做到。

(4)基于(3),DFS不是BFS,不能简单地用它来找最短路,必须要把所有可能的路一一找出来,再逐一比较它们的步数才能确定最短。但题目值允许1000MS,此时就面临一个超时的问题。所以题目才同时给出“步数超过10则视为失败”的条件,这是用来剪枝

 

有了上面的分析,就能最终确定本题的解法了:

DFS+回溯+剪枝

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include<string.h>  
  3. int w,h;//记录场地的宽和高  
  4. int sx,sy,ex,ey;//记录起点和终点坐标  
  5. int dx[4]={0,0,-1,1};//存方向变化量  
  6. int dy[4]={1,-1,0,0};  
  7. int maps[30][30],best;//best记录最优解。maps存地图  
  8.   
  9. void dfs(int cx,int cy,int step)//cx,cy记录当前位置。step表示已走多少步  
  10. {  
  11.     int nx,ny,i;  
  12.     if(step>best)//剪枝如果大于目前最优解直接返回  
  13.         return;  
  14.     for(i=0;i<4;i++)  
  15.     {  
  16.         nx=cx+dx[i];  
  17.         ny=cy+dy[i];  
  18.         if(nx>=h||nx<0||ny>=w||ny<0||maps[nx][ny]==1)//越界或立即有阻挡物剪枝  
  19.             continue;  
  20.         while(nx<h&&nx>=0&&ny<w&&ny>=0&&maps[nx][ny]!=1)//一直滑  
  21.         {  
  22.             if(nx==ex&&ny==ey)//若到终点  
  23.             {  
  24.                 if(step+1<best)  
  25.                     best=step+1;  
  26.                 break;  
  27.             }  
  28.             nx+=dx[i];  
  29.             ny+=dy[i];  
  30.         }  
  31.         if(nx==ex&&ny==ey)//若由于到终点跳出去  
  32.             continue;  
  33.         if(nx<h&&nx>=0&&ny<w&&ny>=0)  
  34.         {  
  35.             maps[nx][ny]=0;//若是碰到阻挡物。阻挡物消失。  
  36.             dfs(nx-dx[i],ny-dy[i],step+1);//继续搜索  
  37.             maps[nx][ny]=1;//还原阻挡物。回溯  
  38.         }  
  39.     }  
  40. }  
  41. int main()  
  42. {  
  43.     int i,j;  
  44.     while(scanf("%d%d",&w,&h),w||h)  
  45.     {  
  46.         best=12;//初始化best  
  47.         for(i=0;i<h;i++)//读取地图  
  48.             for(j=0;j<w;j++)  
  49.             {  
  50.                 scanf("%d",&maps[i][j]);  
  51.                 if(maps[i][j]==2)  
  52.                     sx=i,sy=j;  
  53.                 if(maps[i][j]==3)  
  54.                     ex=i,ey=j;  
  55.             }  
  56.         dfs(sx,sy,0);//深搜  
  57.         if(best<=10)  
  58.             printf("%d\n",best);  
  59.         else  
  60.             printf("-1\n");  
  61.     }  
  62.     return 0;  
  63. }  
0 0
原创粉丝点击