标签:
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; }
标签:
原文地址:http://www.cnblogs.com/nowandforever/p/4542689.html