FZU 2186 小明的迷宫

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;
}


你可能感兴趣的:(dp,广搜,状态压缩,FZU)