題目串連 http://openoj.awaysoft.com/JudgeOnline/problem.php?id=1944
找寶箱
Time Limit: 1 Sec Memory Limit:128 MB
Submit: 235 Solved: 53
[Submit][Status][Web Board]
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 51 -1 1 -1 20 -1 0 -1 00 0 0 0 00 0
Sample Output
12
解題思路:記錄num個寶箱 和其位置(包括出發點) ,計算每兩個之間的最短距離 然後枚舉num的階層種情況(即按排列組合枚舉)
AC代碼:
#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 初始mpfor(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(){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;}next_permutation(a+1,a+num)函數介紹