题目链接: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 }