小明误入迷宫,塞翁失马焉知非福,原来在迷宫中还藏着一些财宝,小明想获得所有的财宝并离开迷宫。因为小明还是学生,还有家庭作业要做,所以他想尽快获得所有财宝并离开迷宫。
有多组测试数据。
每组数据第一行给出两个正整数n,m(0<n,m<=100)。代表迷宫的长和宽。
接着n行,每行m个整数。正数代表财宝(财宝的个数不超过10);负数代表墙,无法通过;0代表通道。
每次移动到相邻的格子,所花费的时间是1秒。小明只能按上、下、左、右四个方向移动。
小明的初始位置是(1,1)。迷宫的出口也在(1,1)。
输出获得所有财宝并逃出迷宫所花费的最小时间,如果无法完成目标则输出-1。
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int maxn=105; int ans,tot,n,m,a[maxn][maxn],f[maxn][maxn],map[15][15],dp[2000][15],F[2000]; int b[4]={0,0,1,-1}; int c[4]={-1,1,0,0}; struct abc { int x,y,t; abc(){} abc(int x,int y,int t):x(x),y(y),t(t){} }; void bfs(int x,int y,int z) { memset(f,0,sizeof(f)); queue<abc> p; p.push(abc(x,y,0)); f[x][y]=1; while (!p.empty()) { abc q=p.front(); p.pop(); if (a[q.x][q.y]>0) map[z][a[q.x][q.y]]=q.t; for (int i=0;i<4;i++) if (q.x+b[i]>0&&q.x+b[i]<=n) if (q.y+c[i]>0&&q.y+c[i]<=m) if (a[q.x+b[i]][q.y+c[i]]>=0) if (!f[q.x+b[i]][q.y+c[i]]) { f[q.x+b[i]][q.y+c[i]]=1; p.push(abc(q.x+b[i],q.y+c[i],q.t+1)); } } } void Bfs() { memset(F,0,sizeof(F)); memset(dp,0,sizeof(dp)); queue<int> p; F[0]=1; for (int i=0;i<=tot-2;i++) { int Q=1<<i; dp[Q][i]=map[1][i+2]; if (F[Q]==0) {F[Q]=1; p.push(Q);} } while (!p.empty()) { int q=p.front(); p.pop(); for (int i=0;i<=tot-2;i++) if (dp[q][i]) for (int j=0;j<=tot-2;j++) { int Q=q|(1<<j); if (Q!=q) { if (!dp[Q][j]) dp[Q][j]=dp[q][i]+map[i+2][j+2]; else dp[Q][j]=min(dp[Q][j],dp[q][i]+map[i+2][j+2]); if (F[Q]==0) {F[Q]=1; p.push(Q);} } } } } int main() { while (~scanf("%d%d",&n,&m)) { ans=0x7FFFFFFF; memset(map,-1,sizeof(map)); tot=0; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { scanf("%d",&a[i][j]); if (a[i][j]>0||i+j==2) { if (a[i][j]<0) ans=-1; a[i][j]=++tot; } } for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (a[i][j]>0) bfs(i,j,a[i][j]); for (int i=2;i<=tot;i++) if (map[1][i]==-1) ans=-1; if (ans>0){ if (tot==1) ans=0; else { Bfs(); for (int i=0;i<=tot-2;i++) { int j=(1<<(tot-1))-1; ans=min(ans,dp[j][i]+map[i+2][1]); } } } printf("%d\n",ans); } return 0; }