Accept: 68 Submit: 496
Time Limit: 1000 mSec Memory Limit : 32768 KB
Problem Description
小明误入迷宫,塞翁失马焉知非福,原来在迷宫中还藏着一些财宝,小明想获得所有的财宝并离开迷宫。因为小明还是学生,还有家庭作业要做,所以他想尽快获得所有财宝并离开迷宫。
Input
有多组测试数据。
每组数据第一行给出两个正整数n,m(0<n,m<=100)。代表迷宫的长和宽。
接着n行,每行m个整数。正数代表财宝(财宝的个数不超过10);负数代表墙,无法通过;0代表通道。
每次移动到相邻的格子,所花费的时间是1秒。小明只能按上、下、左、右四个方向移动。
小明的初始位置是(1,1)。迷宫的出口也在(1,1)。
Output
输出获得所有财宝并逃出迷宫所花费的最小时间,如果无法完成目标则输出-1。
Sample Input
3 3
0 0 0
0 100 0
0 0 0
2 2
1 1
1 1
Sample Output
4
4
先对于每个财宝和起点进行一次广搜确定每个点之间的最短路,
然后2进制状态压缩dp。
#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;
}