搜索(find a way, Pots)

Find a way

思路:这一题看似简单其实不然,有很多特办条件,如果当这个M和Y都在KFC的时候就会导致步数为0 ,或者可以这样说:只有两人都能到达才能算入答案。
  我们可以使用bfs来写这道题,这不过这道题目不需要加入最后的目的地,直接将其全部bfs完,然后使用一个二维数组来存每一个地方的步数就可以了,所以需要两次bfs,需要两个二维数组来存步数。
  然后使用一个结构体数组来存终点的位置
 

我犯下的错误:第一就是bfs还是不能够熟练的使用,我们需要一个变量来存队首,还需要一个变量存改变过后的值,所以我们要插入的值是这个改变的值,而来存队首的变量的值是不能改变的,我经常将不能改变的值改变了,这就导致bfs最后所存下来的图会随着变量的增加而改变。

错误的代码:我将不能改变的变量a改变了,并且还将a给插入到队列了,这就会导致我们存在二位数组中步数就会错,好在我遇到这一题,不然我永远不会知道我错在哪里

 应该将b作为可以改变的对象,只对b进行改变,然后再将b入队。所以正确的代码应该是

 这里还有一个坑点就是输入的问题:时间超限这个问题卡了我很久,一直都不知道是错在哪里。后来在一个大佬的帮助下发现这个输入应该放在while循环中,应该是while(cin >> n >> m)   这样输入就不会导致时间超限,如果将这个放在循环里面就会导致时间超限。

最后一个坑点就是判断输出的问题,我们进行输出的时候就需要进行一个判断,这个判断应该放在最后输出的位置,当M和Y无法同时到达终点的时候不能进行输出。

最终代码如下:

#include<iostream>
#include<string>
#include<map>
#include<queue>
#include<string.h>
#define N 1000000
#define M 350
int n, m,cnt = 0;
using namespace std;
int dx[] = { -1,1,0,0 };
int dy[] = { 0,0,-1,1 };
struct node
{
	int x, y;
}exit_[N];
int step_M[M][M];
int step_Y[M][M];
bool vis[M][M];
char maze[M][M];
int M_x, M_y;
int Y_x, Y_y;
queue<node>q;

void bfs_M(int sx, int sy)
{
	memset(vis, 0, sizeof(vis));
	memset(step_M, 0, sizeof(step_M));
	struct node a, b;
	a.x = sx;
	a.y = sy;
	step_M[a.x][a.y] = 0;
	vis[sx][sy] = 1;
	q.push(a);
	while (!q.empty())
	{
		a = q.front();
		q.pop();
		vis[a.x][a.y] = 1;
		for (int i = 0; i <4; i++) {
			int tx = a.x + dx[i];
			int ty = a.y + dy[i];
			if (tx <= n && tx >= 1 && ty <= m && ty >= 1 && vis[tx][ty] == 0 && maze[tx][ty]!='#') {
				vis[tx][ty] = 1;
				step_M[tx][ty] = step_M[a.x][a.y] + 1;
				b.x = tx;
				b.y = ty;
				q.push(b);
			}
		}
	}
}
void bfs_Y(int sx, int sy)
{
	memset(vis, 0, sizeof(vis));
	memset(step_Y, 0, sizeof(step_Y));
	struct node a, b;
	a.x = sx;
	a.y = sy;
	step_Y[a.x][a.y] = 0;
	vis[sx][sy] = 1;
	q.push(a);
	while (!q.empty())
	{
		a = q.front();
		q.pop();
		vis[a.x][a.y] = 1;
		for (int i = 0; i < 4; i++) {
			int tx = a.x + dx[i];
			int ty = a.y + dy[i];
			if (tx <= n && tx >= 1 && ty <= m && ty >= 1 && vis[tx][ty] == 0&&maze[tx][ty]!= '#') {
				vis[tx][ty] = 1;
				step_Y[tx][ty] = step_Y[a.x][a.y] + 1;
				b.x = tx;
				b.y = ty;
				q.push(b);
			}
		}
	}
}
int main()
{
	while (cin >> n >> m)
	{
		cnt = 0;
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++) {
				cin >> maze[i][j];
				if (maze[i][j] == 'Y') {
					Y_x = i;
					Y_y = j;
				}
				if (maze[i][j] == 'M') {
					M_x = i;
					M_y = j;
				}
				if (maze[i][j] == '@') {
					exit_[++cnt].x = i;
					exit_[cnt].y = j;
				}
			}
			getchar();
		}
		bfs_M(M_x, M_y);
		bfs_Y(Y_x, Y_y); 
		int ans = 2147483647;
		for (int i = 1; i <= cnt; i++) {
			if (step_M[exit_[i].x][exit_[i].y] != 0 && step_Y[exit_[i].x][exit_[i].y] != 0) {
				int t_M = step_M[exit_[i].x][exit_[i].y];
				int t_Y = step_Y[exit_[i].x][exit_[i].y];
				int t = t_M + t_Y;
				ans = min(ans, t);
			}
			
		}
		cout << 11*ans << endl;
	}
}
/*
1.在主函数中输入的时候就将出口位置进行标记,使用一个结构体数组进行标记
2.对于M和Y只需要进行一次bfs即可。
*/

pots

思路:这里一共由三种操作,但是实际上是有6种操作,因为有两个杯子。我们把具体的操作抽象化为数据的操作,我们假设一个杯子的容积为a,那么fill的操作就是令a = a,drop就是使a = 0,

对于第三种操作需要具体考虑若原本a杯子的水加上b杯子的水已经超过了a的容积,那么只需要将a杯子的最大容积减去a杯子现有的容积,然后令a杯子的水等于最大容积,b杯子减去之前算过的a杯子的最大容积减去a杯子现有的容积。第二种情况:就是当b杯子装进去的水小于a杯子最大容积减去a杯子现有的水那么就使a杯子的水等于a杯子现有的水加上b杯子剩余的水。

对于b也同理。

这6种操作当成队列一次入队进行可行性判断,其终止条件是如果有一个杯子的水等于目标杯子那么就跳出循环。

#include<iostream>
#include<string>
#include<map>
#include<queue>
#include<string.h>
using namespace std;
int A, B, C;
bool vis[120][120];
struct node
{
	int a;
	int b;
	int step[100005];
	int sum;
};
bool bfs()
{
	memset(vis, 0, sizeof(vis));
	queue<node> q;
	node x, y;
	x.a = x.b = x.sum = 0;
	vis[x.a][x.b] = 1;
	q.push(x);
	while (!q.empty())
	{
		x = q.front();
		q.pop();
		if (x.a == C || x.b == C) {
			cout << x.sum << endl;
			for (int i = 1; i <= x.sum; i++) {
				if (x.step[i] == 1) cout << "FILL(1)" << endl;
				if (x.step[i] == 2) cout << "FILL(2)" << endl;
				if (x.step[i] == 3) cout << "DROP(1)" << endl;
				if (x.step[i] == 4) cout << "DROP(2)" << endl;
				if (x.step[i] == 5) cout << "POUR(1,2)" << endl;
				if (x.step[i] == 6) cout << "POUR(2,1)" << endl;
			}
			return true;
		}
		for (int i = 1; i <= 6; i++) {
			y = x;
			if (i == 1) y.a = A;
			if (i == 2) y.b = B;
			if (i == 3) y.a = 0;
			if (i == 4) y.b = 0;
			if (i == 5) {
				if (x.a + x.b <= B) {
					y.b = x.a + x.b;
					y.a = 0;
				}
				else {
					y.a = y.a - (B - y.b);
					y.b = B;
				}
			}
			if (i == 6) {
				if (x.a + x.b <= A) {
					y.a = x.a + x.b;
					y.b = 0;
				}
				else {
					y.b = y.b - (A - y.a);
					y.a = A;
				}
			}
			if (!vis[y.a][y.b]) {
				vis[y.a][y.b] = 1;
				y.sum = x.sum + 1;
				y.step[y.sum] = i;
				q.push(y);
			}
		}
	}
	return false;
}
int main()
{
	cin >> A >> B >> C;
	if (!bfs())
	{
		cout << "impossible" << endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白色的风扇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值