【练习06】BFS 1002 Ignatius and the Princess I

算法思路:BFS。

这是一道用BFS求最短路的题,整个代码框架参考自“刘汝佳的《算法竞赛》”,包括bfs()函数和print_path()函数。

关键点:

1.因为存在具有Hp为n的monster存在,如果按照常规的方法直接压入队列,得到的并不会是题目要求的“最短路”,因此必须在处理的过程中想办法当遇到monster的时候在原地等待,等待时间到了之后“自动”的和其他的结点一起继续向“外部”扩散。

处理方法:如果当前位置是monster,那么我就削减他一个HP,再压入队尾,直到HP为0时,继续向四周扩散。

2.路径的打印比较繁琐,需要注意很多的细节,小心点就好了。

另外听人说算法导论上的记忆化BFS可以很好地解决打印问题,具体的操作是建立一个记忆表。

 

弄了一个晚上做这道题,但也是第一道BFS,还是挺开心的!刚开始因为没有注意到“因为monster的存在而不能用常规的BFS做”,但是Sample竟然过了,导致很久没看出来错误的地方,可见这个Sample还是挺阴险的^_^,不过还是要努力地“仔细看题 + 同时训练思维的清晰性”。后来改正了bfs()函数,0msAC,代码如下:

//模板开始
#include <string>   
#include <vector>   
#include <algorithm>   
#include <iostream>   
#include <sstream>   
#include <fstream>   
#include <map>   
#include <set>   
#include <cstdio>   
#include <cmath>   
#include <cstdlib>   
#include <ctime>
#include<iomanip>
#include<string.h>
#define SZ(x) (int(x.size()))
using namespace std;

int toInt(string s){
	istringstream sin(s); 
	int t; 
	sin>>t; 
	return t;
}
template<class T> string toString(T x){
	ostringstream sout; 
	sout<<x; 
	return sout.str();
}
typedef long long int64;
int64 toInt64(string s){
	istringstream sin(s); 
	int64 t; 
	sin>>t;
	return t;
}
template<class T> T gcd(T a, T b){ 
	if(a<0) 
		return gcd(-a, b);
	if(b<0) 
		return gcd(a, -b);
	return (b == 0)? a : gcd(b, a % b);
}
//模板结束(通用部分)

#define ifs cin

#define MAX_LEN 105
char maze[MAX_LEN][MAX_LEN];
int n, m;
int dx[4] = {0, 0, -1, 1};		//分别对应四个方向
int dy[4] = {1, -1, 0, 0};

int vis[MAX_LEN][MAX_LEN];		//结点状态,唯一要注意的是当遇到monster时状态设为-1,表示锁定,结点原地等待,同时不能被相邻的结点访问到,当时间到了之后,需要解锁即状态设为1。
int fa[MAX_LEN][MAX_LEN];		//存储当前结点的下一个结点的“编号”。

//hp和hp1的初始值是一样的,都是monster的HP值,没有monster则为0。
int hp[MAX_LEN][MAX_LEN];		//始终不变,print_path函数中用到
int hp1[MAX_LEN][MAX_LEN];		//动态改变, bfs函数中模拟“遇到monster原地不动”用到

int q[100000];
int front;
int rear;		//指向队列最后一个元素的下一个位置

void bfs(int x, int y)
{
	front = 0;
	rear = 0;
	int d, u;
	u = x * m + y;
	vis[x][y] = 1;
	fa[x][y] = u;
	q[rear++] = u;
	while(front < rear)
	{
		u = q[front++];
		x = u / m;
		y = u % m;

		if(vis[x][y] == -1)		//判断当前结点是否处于锁定状态
		{
			if(hp1[x][y] != 0)
			{
				int v = x * m + y;		//让该结点原地不动,等待
				q[rear++] = v;
				hp1[x][y]--;
				continue;		//继续下一次循环
			}
			else
			{
				vis[x][y] = 1;		//继续下面执行
			}
		}

		for(d = 0; d < 4; d++)
		{
			int nx = x + dx[d];
			int ny = y + dy[d];
			if(vis[x][y] != -1 && nx >= 0 && nx < n && ny >= 0 && ny < m		
				//vis[x][y] == -1表示锁定状态
				&& maze[nx][ny] == '.' && !vis[nx][ny])		//下一个结点是‘.'。
			{
				int v = nx * m + ny;
				q[rear++] = v;
				vis[nx][ny] = 1;
				fa[nx][ny] = u;
				
			}
			else if(vis[x][y] != -1 && nx >= 0 && nx < n && ny >= 0 && ny < m 
				&& maze[nx][ny] != 'X' && !vis[nx][ny] )		//下一个结点是monster。		
			{
				int v = nx * m + ny;
				q[rear++] = v;
				fa[nx][ny] = u;
				vis[nx][ny] = -1;		//设置锁定
			}
		}
	}
}

int xpath[MAX_LEN * MAX_LEN];		//print_path函数用到,用于记录路径上的结点的x坐标。
int ypath[MAX_LEN * MAX_LEN];		//print_path函数用到,用于记录路径上的结点的y坐标。
int c;

void print_path(int x_aim, int y_aim)		//打印路径
{
	if(!vis[x_aim][y_aim])
	{
		cout<<"God please help our poor hero."<<endl<<"FINISH"<<endl;
		return;
	}

	int fight = 0;
	int c = 0;
	for( ; ; )
	{
		int fx = fa[x_aim][y_aim] / m;
		int fy = fa[x_aim][y_aim] % m;
		if(fx == x_aim && fy == y_aim)
		{
			break;
		}
		xpath[c] = x_aim;
		ypath[c] = y_aim;
		if(hp[x_aim][y_aim] != 0)
		{
			fight += hp[x_aim][y_aim];
		}
		c++;
		x_aim = fx;
		y_aim = fy;
	}

	xpath[c] = x_aim;		//补上最后一次执行的值。循环中并没有执行这一次!
	ypath[c] = y_aim;		//这样的话c的值刚刚好等于“步数 = 路径上点的个数 - 1”。
	if(hp[x_aim][y_aim] != 0)		//虽然题目说起点没有monster,但是判断一下也可以,防止测试数据出错
	{
		fight += hp[x_aim][y_aim];
	}

	int time = 1;
	int temp;
	cout<<"It takes "<<c + fight 
		<<" seconds to reach the target position, let me show you the way."<<endl;
	for(temp = c; temp >= 1; temp--)
	{
		if(hp[xpath[temp]][ypath[temp]] == 0)
		{
			cout<<time++<<"s:("<<xpath[temp]<<","
				<<ypath[temp]<<")->("<<xpath[temp - 1]
			<<","<<ypath[temp - 1]<<")"<<endl;
		}
		else
		{
			while(hp[xpath[temp]][ypath[temp]] != 0)
			{
				cout<<time++<<"s:FIGHT AT ("<<xpath[temp]<<","
					<<ypath[temp]<<")"<<endl;
				hp[xpath[temp]][ypath[temp]]--;
			}
			cout<<time++<<"s:("<<xpath[temp]<<","
				<<ypath[temp]<<")->("<<xpath[temp - 1]
			<<","<<ypath[temp - 1]<<")"<<endl;
		}
	}
	if(hp[xpath[temp]][ypath[temp]] != 0)		//虽然起点不会是monster,但是终点有可能是!
	{
		while(hp[xpath[temp]][ypath[temp]] != 0)
		{
			cout<<time++<<"s:FIGHT AT ("<<xpath[temp]<<","
				<<ypath[temp]<<")"<<endl;
			hp[xpath[temp]][ypath[temp]]--;
		}
	}
	cout<<"FINISH"<<endl;
}

//【练习06】BFS 1002 Ignatius and the Princess I

int main()
{
	//ifstream ifs("shuju.txt", ios::in);
	while(ifs>>n>>m)
	{
		for(int i = 0; i < n; i++)
		{
			for(int j = 0; j < m; j++)
			{
				vis[i][j] = 0;

				ifs>>maze[i][j];
				if(maze[i][j] ==  '.')
				{
					hp[i][j] = 0;
					hp1[i][j] = 0;
				}
				else if(maze[i][j] != 'X')
				{
					hp[i][j] = int(maze[i][j] - '0');
					hp1[i][j] = int(maze[i][j] - '0');
				}
			}
		}

		bfs(0, 0);
		print_path(n - 1, m - 1);
	}

	return 0;
}


 

weixin073智慧旅游平台开发微信小程序+ssm后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值