bfs,分层图,最短路径,牛客小白月赛75-D矩阵

D-矩阵_牛客小白月赛75 (nowcoder.com)

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

题目描述

现有一个大小为n×mn\times mn×m的二维矩阵,每个元素si,js_{i,j}si,j​可能是字符'0'、'1'。
阿宁一开始站在(1,1)(1,1)(1,1),目标走到(n,m)(n,m)(n,m)。
假设当前在(x,y)(x,y)(x,y),一个相邻位置(x′,y′)(x',y')(x′,y′) ,上下左右 相邻。可以进行以下其中一个行为,花费一个单位时间:
1. 如果sx,ys_{x,y}sx,y​是'0',sx′,y′s_{x',y'}sx′,y′​是'1',可以从(x,y)(x,y)(x,y)走到(x′,y′)(x',y')(x′,y′)。
2. 如果sx,ys_{x,y}sx,y​是'1',sx′,y′s_{x',y'}sx′,y′​是'0',可以从(x,y)(x,y)(x,y)走到(x′,y′)(x',y')(x′,y′)。
3. 将sx′,y′s_{x',y'}sx′,y′​变成'1'。
4. 将sx′,y′s_{x',y'}sx′,y′​变成'0'。

问阿宁从(1,1)(1,1)(1,1)走到(n,m)(n,m)(n,m)需要最少多少单位时间?

输入描述:

第一行输入两个正整数n,mn,mn,m。
接下来输入nnn行,每行mmm个字符,字符仅包含'0'、'1'。
1≤n,m≤10^3

输出描述:

 

输出一个整数。


这是一道典型的分层图的bfs


分层图:
1、一般用于边或点有特殊限制的问题(如:重复经过多次、多种价值可选)
2、将点拆开,复制多层图,并利用特殊构造的边将各层相连的建图方法
3、需要保证拆开后的总点数规模可接受

这道题建立两层分层图就可以了,只改变下层的点:当要改变点时将目标点下层的点改变,距离加2,然后将该点放入优先队列
注意:这里用的是优先队列,因为它每次加的距离不是一样的了,有时加1,有时加2,因此我们需要用优先队列才能用bfs来处理这种就短距离问题
 


#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<map>
#include<math.h>
#include<stack>


using namespace std;
typedef long long LL;
const int N = 1e3 + 5;
string str[2][N];
int n, m, v[2][N][N];
int ay[] = { 0,0,1,-1 }, ax[] = { -1,1,0,0 };

typedef struct st {
	int c, y, x, d;
}st;

bool operator > (const st& a, const st& b) {
	return a.d > b.d;
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> str[0][i];
		str[0][i].insert(0, " ");
		str[1][i] = str[0][i];
	}
	vector<int>p;
	priority_queue<st, vector<st>, greater<st>>q;
	q.push({ 0,1,1,0 });
	v[0][1][1] = 1;
	st t;
	while (!q.empty()) {
		t = q.top();
		q.pop();

		//cout << t.c << " " << t.y << " " << t.x << " " << t.d << endl;

		if (t.y == n && t.x == m) {
			p.push_back(t.d);
			if (p.size() == 2)
				break;
		}
		for (int i = 1,y,x; i < 4; i++) {
			y = t.y + ay[i];
			x = t.x + ax[i];
			if (y<1 || y>n || x > m || x < 1)
				continue;
			if (str[0][y][x] == str[t.c][t.y][t.x]) {
				if (v[1][y][x] == 0) {
					v[1][y][x] = 1;
					if (str[0][y][x] == '1')
						str[1][y][x] = '0';
					else 
						str[1][y][x] = '1';
					q.push({ 1,y,x,t.d + 2 });
				}
				continue;
			}
			if (v[0][y][x] == 1)
				continue;
			v[0][y][x] = 1;
			q.push({ 0,y,x,t.d + 1 });
		}
	}
	sort(p.begin(), p.end());
	cout << p[0] << endl;
	return 0;
}

这里再补充另一个分层图的做法

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N = 1e3 + 5;
int n, m;
string str[N];
int d[N][N][3], v[N][N][3];
int ay[4] = { 0,0,-1,1 }, ax[] = {1,-1,0,0};
typedef struct st {
	int y, x, c;
}st;

int bfs() {
	memset(d, 0x3f, sizeof(d));
	d[1][1][0] = 0;
	v[1][1][0] = 1;
	queue<st>q;
	q.push({ 1,1,0 });	
	int y, x,c;
	while (!q.empty()) {
		y = q.front().y;
		x = q.front().x;
		c = q.front().c;
		q.pop();
		if (c == 2) {
			if (v[y][x][1] == 0) {
				d[y][x][1] = d[y][x][2] + 1;
				v[y][x][1] = 1;
				q.push({ y,x,1 });
			}
		}
		else {
			for (int i = 0; i < 4; i++) {
				int ty = y + ay[i], tx = x + ax[i];
				if (ty<1 || ty>n || tx<1 || tx>m)continue;
				if (c == 0) {
					if (str[ty][tx] == str[y][x]) {
						if (v[ty][tx][2] == 0) {
							d[ty][tx][2] = d[y][x][0] + 1;
							v[ty][tx][2] = 1;
							q.push({ ty,tx,2 });
						}
					}
					else {
						if (v[ty][tx][0] == 0) {
							d[ty][tx][0] = d[y][x][0] + 1;
							v[ty][tx][0] = 1;
							q.push({ ty,tx,0 });
						}
					}
				}
				else {
					if (str[ty][tx] == str[y][x]) {
						if (v[ty][tx][0] == 0) {
							d[ty][tx][0] = d[y][x][1] + 1;
							v[ty][tx][0] = 1;
							q.push({ ty,tx,0 });
						}
					}
					else {
						if (v[ty][tx][2] == 0) {
							d[ty][tx][2] = d[y][x][1] + 1;
							v[ty][tx][2] = 1;
							q.push({ ty,tx,2 });
						}
					}
				}
			}
		}
	}
	return min(d[n][m][0],d[n][m][1]);
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		cin >> str[i];
		str[i].insert(0, " ");
	}
	int ans=bfs();
	printf("%d\n", ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值