码迷,mamicode.com
首页 > 其他好文 > 详细

HDU ACM 1044 Collect More Jewels BFS+DFS

时间:2015-06-05 22:45:56      阅读:283      评论:0      收藏:0      [点我收藏+]

标签:c   c++   acm   算法   编程   

题意:在一个迷宫中,有一些宝物,从起点走到终点,问在给定的时间内,到达终点后所能拾取珠宝的最大价值。

分析(BFS+DFS):
1、求入口到第一个取宝物的地方的最短距离
2、求第i个取宝物的地方到第i+1个取宝物的地方的最短距离
3、求第n个取宝物的地方到出口的最短距离
4、保证以上3点能在时间L内实现的情况下,取得的宝石价值最大。
BFS特点:对于解决最短或最少问题特别有效,而且寻找深度小,但缺点是内存耗费量大(需要开大量的数组单元来存储状态)

DFS特点:对于解决遍历和求所有问题有效,对于问题搜索深度小的时候处理速度迅速,然而在深度很大的情况下效率不高。

对整个图做bfs,bfs求得某个点(入口、出口、珠宝)到另外一个点之间的最短距离。bfs过程中构建隐式图,然后从入口处开始进行dfs搜索构造的隐式图,更新ans。

PS:该題还能用BFS+状态压缩做,但效率不高。

将宝物状态压缩,对于l个珍宝,可以用l位二进制表示珍宝的获取情况(1表示获得,0未获得)。然后用vis[i][j][k]表示状态,i表示珍宝获取情况,(j,k)表示位置。这样相当于走2^l张地图,每次得到珍宝时转换地图,这样就需要相当多的时间消耗了。在bfs+dfs中,珍宝至多10件,可以找出起点到所有珍宝和终点的最短路径,珍宝到其他珍宝和终点的最短路径。需要bfs地图至多21次,比上面的2^l次要少很多。因此BFS+DFS效率高。

#include<iostream>
#include<queue>
using namespace std;

#define N 60
int W,H,L,M;   //地图是W列H行,时间限制L,宝石数量M
int val[N];      //宝石的价值
char map[N][N];  //地图
bool bfsvis[N][N];   //BFS访问标记
bool dfsvis[N];   //dfs访问标记
int step[N][N];      //bfs中访问步长

int ans,sum;        //结果,宝石总价值
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
int dis[N][N];       //记录开始位置,结束位置,各宝石位置两两之间的距离

void BFS(int cx,int cy,int s) //求解(cx,cy)到其他点的距离,s(0-M+1),0表示开始位置,M+1出口,其他宝石位置
{
	queue<int> q;
	int u,i,x,y,x2,y2;

	memset(bfsvis,false,sizeof(bfsvis));
	memset(step,0,sizeof(step));
	u=cx*W+cy;      //初始点
	q.push(u);
	bfsvis[cx][cy]=true;
	step[cx][cy]=0;
	while(!q.empty())
	{
		u=q.front();
		q.pop();
		x=u/W;
		y=u%W;
		for(i=0;i<4;i++)      //四个方向
		{
			x2=x+dir[i][0];
			y2=y+dir[i][1];
			if(x2<0||x2>=H||y2<0||y2>=W||bfsvis[x2][y2]||map[x2][y2]=='*')
				continue;
			bfsvis[x2][y2]=true;
			step[x2][y2]=step[x][y]+1;    //步长加1
			if(map[x2][y2]=='@') dis[s][0]=step[x2][y2];  //其他点到起点
			else if(map[x2][y2]=='<') dis[s][M+1]=step[x2][y2]; //其他点到终点
			else if(map[x2][y2]>='A' && map[x2][y2]<='J')  //其他点到宝石点
				dis[s][map[x2][y2]-'A'+1]=step[x2][y2];
			q.push(x2*W+y2);
		}
	}
}

void DFS(int s,int value,int t) //s当前点,value当前获得的价值,t当前花费的时间
{
	int i;

	if(t>L)        //超时
		return ;
	if(ans==sum)   //宝石已全部获取,剪枝
		return ;
	if(s>M)        //已到出口
	{
		if(value>ans)
			ans=value;
		return ;
	}
	for(i=0;i<=M+1;i++)
	{
		if(dis[s][i]==0 || dfsvis[i]) //自己到自己或者已经访问过
			continue;
		dfsvis[i]=true;
		DFS(i,value+val[i],t+dis[s][i]);
		dfsvis[i]=false;
	}
}

int main()
{
	int T,i,j,t=0;

	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d%d",&W,&H,&L,&M);
		sum=0;
		for(i=1;i<=M;i++)
		{
			scanf("%d",&val[i]);
			sum+=val[i];
		}
		val[0]=val[M+1]=0;
		for(i=0;i<H;i++)
			scanf("%s",map[i]);
		memset(dis,0,sizeof(dis));
		for(i=0;i<H;i++)                //BFS对相关点处理
			for(j=0;j<W;j++)
				if(map[i][j]=='@')
					BFS(i,j,0);
				else if(map[i][j]=='<')
					BFS(i,j,M+1);
				else if(map[i][j]>='A' && map[i][j]<='Z')
					BFS(i,j,map[i][j]-'A'+1);
		ans=-1;
		memset(dfsvis,false,sizeof(dfsvis));
		dfsvis[0]=true;
		DFS(0,0,0);
		cout<<"Case "<<++t<<":"<<endl;
		if(ans>=0)
			cout<<"The best score is "<<ans<<"."<<endl;
		else
			cout<<"Impossible"<<endl;
		if(T>0)
			cout<<endl;
	}
    return 0;      
}


HDU ACM 1044 Collect More Jewels BFS+DFS

标签:c   c++   acm   算法   编程   

原文地址:http://blog.csdn.net/a809146548/article/details/46381003

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!