hdoj1044,Collect More Jewels

本文介绍了解决HDOJ 1044问题的方法,通过构建新图并结合广度优先搜索(BFS)与深度优先搜索(DFS)来寻找最大值。讨论了剪枝技巧以及测试策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.首先这个没有过,超时。虽然用了深搜,超时。后来在网上看到别人写的答案,仿照着写,还是超时。自己又找不到错误。就贴出来,待以后在看看。

2.若是用深搜或者广搜,应该很简单。当然,应该想尽办法剪枝。但是,由于求最大值,有些枝是减不掉的。

3.后来参考网上答案,点击打开链接,仿写了一个,但是还是超时,我也没找到问题所在,就先这样。

4.整体的思路就是先根据原来的图确定各个特殊点之间的相互距离在构建一个新的图,这是用bfs。然后用新的图dfs,找到最小值。这样理论上可以过,不超时。

5.在如何进到bfs里面是使用判断,因为就新图而言,每一行都是同一个点到别的点的距离。所以要找到所有的点然后再bfs,main函数里的循环就是这个意思。

6.bfs是正常的bfs,因为不算main里面的循环,这个bfs没什么特别,唯一的特别就是没找到一个特殊点就需要把他记到新图里去。

7,dfs里面除了剪枝,也都是正常的。剪枝,也就是那几个条件,要考虑新图的特殊之处。比如当value等于所有value的和时,他一定已经走到了最后,当然,所有条件都不能反过来。也就是反过来是不成立的。

8,最后说一下测试。应该采用先整体测试一些,有输出,然后如果问题解决不了,就在分布测试。在这类广搜或者深搜中,尽力吧步数或者中间值输出来,比如这个,把新的图    输出来就会好很多。

深搜代码:

/*
content     :  hdoj1044
author      :  kaka
time        :  2015/09/08
1.深搜提交版
*/

#include<iostream>
#include<queue>
using namespace std;
struct Node
{
	int x;
	int y;
	char c;
	int value;
};
int nextX[4]={0,1,0,-1};
int nextY[4]={1,0,-1,0};
int w,h,l,m;
int sx,sy,ex,ey;
int maxNum;
int maxNum1;
bool flag;
const int maxn = 50;
Node maze[maxn][maxn];
void bfs();
void dfs(int,int,int);
int Value[10];
int main()
{
    int t;
	cin>>t;
	int tempT = 1;
	while(tempT<=t)
	{
		//cout << " tempT: "<<tempT << " t: " << t<<endl;
		//记录下墙的数目用来剪枝
		int count=0;
		cin>>w>>h>>l>>m;
		//cout << " main: 39: " << w<<" " <<h<<" "<<l<<" "<<m<<endl;
		for ( int i = 0; i < m; i++)
			cin>>Value[i];
		for(int i = 0; i < h; i++)
		{
			for ( int j = 0; j < w; j++)
			{
				cin>>maze[i][j].c;
				maze[i][j].x = i;
				maze[i][j].y = j;
				maze[i][j].value = 0;
				if(maze[i][j].c=='@')
				{
					sx = i;
					sy = j;
				}
				if(maze[i][j].c=='<')
				{
					ex = i;
					ey =j;
				}

			}
		}
		maxNum1 = 0;
		maxNum = 0;
		cout <<"Case "<<tempT<<":"<<endl;
		//这个不能这样剪枝。
		if(l < abs(ex-sx)+abs(ey-sy))
		{
			cout << "Impossible"<<endl;
			continue;
		}
		dfs(sx,sy,0);
		if(flag)
		{
			cout << "The best score is "<<maxNum<<".";
		}
		else cout << "Impossible"<<endl;
		cout << endl;
		if(tempT<t)
			cout <<endl;
		tempT++;

	}
	return 0;
}

void dfs(int x, int y,int step)
{
	
	if(maze[x][y].c=='<'&&step==l)
	{
		flag = true;
		if(maxNum < maxNum1)
			maxNum = maxNum1;
		maxNum1= 0;
		
		return;
	}
	if(step==l&&maze[x][y].c!='<')
	{
		return;
	}
	
	int temp = l - abs(ex-x)-abs(ey-y)-step;
	if(temp <0 ||temp%2!=0)
	{
		return;
	}

	for ( int i = 0; i < 4; i++ )
	{
		int nx = x+nextX[i];
		int ny = y+nextY[i];
		if(nx<0||nx>=h||ny<0||ny>=w)
		{
			continue;
		}
		if(maze[nx][ny].c =='.'||maze[nx][ny].c=='<')
		{
			dfs(nx,ny,step+1);
		}
		else if((maze[nx][ny].c -'A')>=0&&(maze[nx][ny].c -'A')<=11)
		{
			temp = maze[nx][ny].c-'A';
			maxNum1+=Value[temp];
			dfs(nx,ny,step+1);
		}
	}
}

参考网上写的版本:

/*
content		:		hdoj,可以ac的解法
author      :		kaka
time        :		2012/09/10
reference   :		http://blog.youkuaiyun.com/dzyhenry/article/details/8847828
*/


#include<queue>
#include<iostream>

using namespace std;
//数组最大的尺寸
const int con1 = 60;
//记录所有的value值用来剪枝
int allValue ;
//原来的迷宫
char maze[con1][con1];
//标记原来和后来的迷宫某一点是否已经被访问了
int visited[con1][con1];
//记录每一个标志点到别的点的距离。
int dis[con1][con1];
//标记新的
bool visited2[con1];
//记录珠宝值
int Value[10];
//新的迷宫,有各个标志点之间的距离组成。
struct NewNode
{
	int x;
	int y;
	//int value;
};
//新的迷宫
int newMaze[con1][con1];
//四个方向
int nextX[4] = {0,1,0,-1};
int nextY[4] = {1,0,-1,0};
int w,h,l,m;
//使用广搜构筑新的迷宫
void bfs(int, int ,int);
//使用深搜找到解
void dfs(int, int, int);
//一个标志,是否有解
bool flag ;
//最大值
queue<NewNode> q;
int maxValue;
int main()
{
    int t;
	cin>>t;
	int tempT = 1;
	int sx, sy,ex,ey;
	while(tempT<=t)
	{
		//cout << " tempT: "<<tempT << " t: " << t<<endl;
		//记录下墙的数目用来剪枝
		int count=0;
		memset(Value, 0, sizeof(Value));  
        memset(newMaze, 0, sizeof(newMaze));
		memset(visited2,0,sizeof(visited2));
		cin>>w>>h>>l>>m;
		//cout << " main: 39: " << w<<" " <<h<<" "<<l<<" "<<m<<endl;

		for ( int i = 1; i <=m; i++)
		{
			cin>>Value[i];
			allValue+=Value[i];
		}
		Value[0]=Value[m+1]=0;
		for(int i = 0; i < h; i++)
		{
			for ( int j = 0; j < w; j++)
			{
				cin>>maze[i][j];
				
				if(maze[i][j]=='@')
				{
					sx = i;
					sy = j;
				}
				
				if(maze[i][j]=='<')
				{
					ex = i;
					ey = j;
				}
				
			}
		}
		maxValue = 0;
		//allValue = 0;
		cout <<"Case "<<tempT<<":"<<endl;
		//这个不能这样剪枝。
		
		if(l < abs(ex-sx)+abs(ey-sy))
		{
			cout << "Impossible"<<endl;
			if(tempT<t)
			cout <<endl;
			continue;
		}
		
		//memset(visited,0,sizeof(visited));
		//memset(dis,0,sizeof(dis));
		for ( int i = 0; i <h;i++)
		{
			for ( int j = 0; j < w; j++)
			{
				
				if(maze[i][j]=='@')
				{
					memset(visited,0,sizeof(visited));
		        memset(dis,0,sizeof(dis));
					bfs(i,j,0);
				}
				 if(isalpha(maze[i][j]))
				{
					memset(visited,0,sizeof(visited));
		        memset(dis,0,sizeof(dis));
					bfs(i,j,maze[i][j]-'A'+1);
				}
				 if(maze[i][j]=='<')
				{
					memset(visited,0,sizeof(visited));
		        memset(dis,0,sizeof(dis));
					bfs(i,j,m+1);
				}
			}
		}

		//测试新的迷宫
		//for ( int i = 0;i < m+2; i++ )
		//{
		//	for ( int j = 0; j < m+2;j++ )
		//	{
		//		cout << newMaze[i][j];
		////	}
		//	cout <<endl;
		//}
		memset(visited,0,sizeof(visited));
		maxValue = -1;
		visited2[0] = 1;
		dfs(0,0,0);
		//等于0也是可以的,因为可能有没有的。
		if(maxValue>=0)
		{
			cout << "The best score is "<<maxValue<<".";
		}
		else cout << "Impossible"<<endl;
		cout << endl;
		if(tempT<t)
			cout <<endl;
		tempT++;

	}
	return 0;
}

void bfs(int x, int y, int num)
{
	
	//cout << " main: 152: x,y,num: " <<x<<" " << y<<" " <<num<<endl;
	NewNode newNode ; 
	while(!q.empty())
		q.pop();
	
	newNode.x = x;
	newNode.y = y;
	dis[x][y] = 0;
	visited[x][y] = 1;
	q.push(newNode);
	while(!q.empty())
	{
		newNode = q.front();
		q.pop();
		//cout <<"main: 167: x,y: " << newNode.x<<" " << newNode.y<<endl;
		for ( int i = 0; i < 4; i++ )
		{
			NewNode nextNode ;
			nextNode.x = newNode.x+nextX[i];
			nextNode.y = newNode.y+nextY[i];
			//cout <<"main:172: 
			if(nextNode.x<0||nextNode.x>=h||nextNode.y<0||nextNode.y>=w)
				continue;
			if(visited[nextNode.x][nextNode.y]==0&&maze[nextNode.x][nextNode.y]!='*')
			{
				dis[nextNode.x][nextNode.y]=dis[newNode.x][newNode.y]+1;
				visited[nextNode.x][nextNode.y]=1;
				if(maze[nextNode.x][nextNode.y]=='@')
				{
					newMaze[num][0]=dis[nextNode.x][nextNode.y];
				}
				if(maze[nextNode.x][nextNode.y]=='<')
				{
					newMaze[num][m+1]=dis[nextNode.x][nextNode.y];
				}
				if(isalpha(maze[nextNode.x][nextNode.y]))
				{
					newMaze[num][maze[nextNode.x][nextNode.y]-'A'+1]=dis[nextNode.x][nextNode.y];
				}
				q.push(nextNode);
			}
		}
	}

}

void dfs(int num, int value, int time)
{
	//cout << "main203: value: time:"<<value<<" " <<time<<endl;
	//cout << "main204: maxValue: " <<maxValue<<endl;
	//下面的条件是由于新的地图的特点造成的。
	if(time>l||value==allValue)
		return;
	if(num>m&&value>maxValue)
	{
		maxValue = value;
	}
	for ( int i = 0; i <=m+1; i++ )
	{
		if(newMaze[num][i]==0||visited2[i])
			continue;
		visited2[i]=1;
		dfs(i, value+Value[i],time+newMaze[num][i]);
		visited2[i] = 0;
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值