找宝箱 (bfs)
Problem Description
作为一个强迫症患者,小 Y 在走游戏里的迷宫时一定要把所有的宝箱收集齐才肯罢休。现在给你一个 N *M 的迷宫,里面有障碍、空地和宝箱,小 Y 在某个起始点,每一步小 Y 可以往上下左右走,当然前提时没有走出迷宫并且走到的点不是障碍。如果小 Y 走到了某个为宝箱的点,那么这个宝箱就被他收集到了,然后此处变为空地。 现在你需要计算小 Y 最少需要走多少步才能收集齐所有的宝箱。
Input
输入包含多组数据。 对于每组数据,第一行两个正整数 N;M(1<=N;M<=100),表示迷宫大小。 接下来 N 行,每行 M 个整数,第 i + 1 行的第 j 个整数表示迷宫第 i 行第 j 列的情况,0 表示空地,-1表示障碍,1 表示宝箱,2 表示小Y 的起始点。保证2 只有一个,且宝箱数量不超过5 个。 数据以两个0 表示结尾。
Output
对于每组数据输出一行,包含一个整数,表示小 Y 最少的步数。如果小 Y 无法收集齐所有宝箱,输出-1。
Sample Input
3 5 1 -1 1 -1 2 0 -1 0 -1 0 0 0 0 0 0 0 0
很久之前遇到的题现在又偶然遇到了,当初一直没看懂,现在终于懂了,不过找不到出处在哪了。
因为要收集完所有宝箱,把起点也作为宝箱,然后求出所有宝箱的两两距离,最后枚举所有 的情况求出最小值.
枚举的时候借用了全排列,方法很巧妙。
#include<iostream> #include<cstring> #include<stdio.h> #include<queue> #include<algorithm> using namespace std; const int M=205; int n,m; int map[M][M]; //迷宫 struct point { int r; int l; } p[7]; //记录宝箱位置和初始位置 int run[4][2]= {1,0,-1,0,0,1,0,-1}; //bfs的方向数组 int bfs(point x,point y) //求两个宝箱的最短距离 { int r,l,i,now,next,a[M][M]= {0},mp[M][M]; queue<int> qu; now=x.r*m+x.l; qu.push(now); for(i=0; i<n; i++) //因为要调用计算多次,所以map不能改变,每次用map 初始mp for(l=0; l<m; l++) mp[i][l]=map[i][l]; while(!qu.empty()) { now=qu.front(); qu.pop(); for(i=0; i<4; i++) { r=now/m+run[i][0]; l=now%m+run[i][1]; next=r*m+l; if(r>=0 &&r<n && l>=0 && l<m && mp[r][l]!=-1) { a[r][l]+=a[now/m][now%m]+1; qu.push(next); mp[r][l]=-1; if(r==y.r && l==y.l) return a[r][l]; } } } return -1; //不通时返回 } int main() { freopen("a.txt","r",stdin); int i,j,num,min,dis[M][M];//dis数组保存第i个宝箱到第j个宝箱的最短距离 while(scanf("%d%d",&n,&m)!=EOF && n!=0 && m!=0) { memset(dis,0,sizeof(dis)); int flag=0;//若有宝箱不能到达的标志 min=10000000; num=1; for(i=0; i<n; i++) for(j=0; j<m; j++) { cin>>map[i][j]; if(map[i][j]==2) { p[0].r=i; p[0].l=j; } if(map[i][j]==1 ) { p[num].r=i; p[num++].l=j; } } for(i=0; i<num; i++) { for(j=0; j<num; j++) if(i!=j) { dis[i][j]=bfs(p[i],p[j]); if(dis[i][j]==-1) { flag=1; break; } } if(flag) break; } if(flag) { printf("-1\n"); continue; } char a[7]= {"012345"}; //因为最多有5个宝箱,用这个字符串代表排列的顺序,看下面会懂的,有点妙! do { int s=0; for(i=0; i<num-1; i++) { s+=dis[a[i]-'0'][a[i+1]-'0']; } if(min>s) //判断每种情况, min=s; } while(next_permutation(a+1,a+num)); //一个库函数 第一次经过他之后a[6]={"02354"} printf("%d\n",min); } return 0; }