专题一 简单搜索 Problem I

题目链接:http://acm.fzu.edu.cn/problem.php?pid=2150

题目大意:给一张n*m的矩形地图,上面有的点是草地,有的点是土地。

     从中挑选两个草地点,将其点燃。问最少多长时间能将该地图上的所有草地都烧完。若不能,输出-1。

     已知在t时刻点燃该草地点时,t+1时刻该点的上下左右的草地点也被点燃。

解题思路:bfs搜索。

     以两点为起点搜索,直到不能扩展。

     如果草地点数目小于等于2,则直接烧完,返回0。

     把所有的草地点拿出来,每次取两点得出一个时间,取最小值。

注意:从中找出的两点不一定能把所有草地烧完。循环结束后要判断。

代码如下:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 using namespace std;
  5 #define MAXN 12
  6 #define INF 99999999
  7 
  8 int cnt,n,m;//分别表示草地的个数,地图的行和列
  9 char Map[MAXN][MAXN];//描述地图
 10 struct Point
 11 {
 12     int x,y,step;//描述地图上的每一个点
 13 };
 14 Point List[MAXN*MAXN];//将地图上所有的草地点放入该列表
 15 Point Queue[MAXN*MAXN];//模拟队列实现过程
 16 bool vis[MAXN][MAXN];//标记某点是否走过
 17 int dirx[]={0,0,1,-1};//方向数组
 18 int diry[]={1,-1,0,0};//方向数组
 19 
 20 int check(int x,int y)//该函数判断某点是否在地图内部
 21 {
 22     if(x>=0 && x<n && y>=0 && y<m)
 23         return 1;
 24     else
 25         return 0;
 26 }
 27 
 28 int MIN(int a,int b)
 29 {
 30     if(a<=b)
 31         return a;
 32     else
 33         return b;
 34 }
 35 
 36 int bfs(Point a,Point b)//从两草地出发,烧完所有的草地所需要的时间
 37 {
 38     memset(vis,0,sizeof(vis));//初始化
 39 
 40     int head=0,tail=0;
 41     Queue[tail++]=a;//将两点放入队列
 42     Queue[tail++]=b;//将两点放入队列
 43     vis[a.x][a.y]=1;//标记
 44     vis[b.x][b.y]=1;//标记
 45 
 46     int ans;
 47     while(head<tail)//队列非空时循环
 48     {
 49         Point p=Queue[head++];//从队首取出一点,抛弃队首
 50         ans=p.step;
 51 
 52         for(int i=0;i<4;i++)//向四个方向扩展
 53         {
 54             Point temp;
 55             temp.x=p.x+dirx[i];
 56             temp.y=p.y+diry[i];
 57             temp.step=p.step+1;
 58             if( (check(temp.x,temp.y)) && (!vis[temp.x][temp.y]) && (Map[temp.x][temp.y]=='#') )
 59             {
 60                 vis[temp.x][temp.y]=1;
 61                 Queue[tail++]=temp;//如果当前点可扩展,标记并放入队尾 
 62             }
 63         }
 64     }
 65     //该循环结束时,有的点可能没被扩展过
 66     for(int i=0;i<n;i++)
 67     {
 68         for(int j=0;j<m;j++)
 69         {
 70             if(Map[i][j]=='#' && vis[i][j]==0) ans=0;//判断地图上的所有草地是否被扩展过,如果有,则说明该方法不能烧完所有草地
 71         }
 72     }
 73     
 74     return ans==0?-1:ans;
 75 }
 76 
 77 int main()
 78 {
 79     int cases,num=0;
 80     scanf("%d",&cases);
 81     while(cases--)
 82     {
 83         scanf("%d %d",&n,&m);
 84         getchar();
 85 
 86         cnt=0;
 87         for(int i=0;i<n;i++)
 88         {
 89             for(int j=0;j<m;j++)
 90             {
 91                 scanf("%c",&Map[i][j]);
 92                 if(Map[i][j]=='#')
 93                 {
 94                     Point temp;
 95                     temp.x=i;
 96                     temp.y=j;
 97                     temp.step=0;
 98                     List[cnt++]=temp;//将所有草地放入列表
 99                 }
100             }
101             getchar();
102         }
103         if(cnt<=2)//如果草地数小于等于2,则直接烧光
104         {
105             printf("Case %d: 0\n",++num);
106             continue;
107         }
108         int res=INF;
109         for(int i=0;i<cnt-1;i++)//从列表中拿出两点,算出时间,找到最小时间。如果找不到,返回-1。
110         {
111             for(int j=i+1;j<cnt;j++)
112             {
113                 if(bfs(List[i],List[j])!=-1)
114                     res=MIN(res,bfs(List[i],List[j]));
115             }
116         }
117         printf("Case %d: %d\n",++num,res==INF?-1:res);
118     }
119     return 0;
120 }
View Code

 

你可能感兴趣的:(专题一 简单搜索 Problem I)