[蓝桥杯][历届试题]九宫重排

题目

题目链接

题解

BFS。


先讲标准做法,对应代码2:

map类型的vis记录某个状态是否经历过;什么是状态,状态就是比如12345678.123.46758,这些string型的数值就对应着一个个状态,即网格中数字和空格的不同排法。

pair 知识点:
队列中结点的类型为pair<string, int>pair<string, int>相当于一个结构体里面有两个元素,一个是string类型,另一个是int类型,分别记录状态和到达此状态的步数。pair的第一个元素通过.first访问,第二个元素通过.second访问。
习惯上,我们一般直接将pair<int, int> typedefPII,类似地,我将pair<string, int> typedefPSI。另外还习惯上将first definexsecond definey,但是我不习惯。

每次扩展儿子结点都是让空格去上下左右移动,让空格与满足条件的位置上的数交换,插入队列,不断循环直至到达目标状态或无可扩展结点,输出结果。

这个耗时比较卡点,再多点奇奇怪怪的操作就TLE了。


再将最为重要的双向广搜,因为我也是第一次用,所以好好讲讲(虽然没什么好讲的)
对应代码1。

正如它的名字一样,从初始状态和目标状态同时进行BFS,当其中一个搜索搜索到了一个两个搜索都搜索过的状态了,那么从初始状态到目标状态的最小步数就是第一个搜索记录的步数与第二个搜索记录的步数之和。
道理也很简单,不予证明。

会写广搜的,随便扫一眼就会了。

提几点注意:

  • 这里的map类型要保存的是到达某状态的步数,而不仅仅是是否到达过了。
  • 结束条件是同一个字符串在两个map中都存在。

最后一个代码3,随便看看就得了,图一乐,我的垃圾做法。

代码1:双向广搜

// 双向广搜 53s
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<string, int> PSI;

int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
int ans = -1;

queue<PSI> Q1, Q2;

string ss, tt;

map<string, int> step1, step2;

int main()
{
	cin>>ss>>tt;
	
	Q1.push(PSI(ss, 0));
	Q2.push(PSI(tt, 0));
	step1[ss] = 0;
	step2[tt] = 0;
	
	
	while(!Q1.empty() && !Q2.empty()) {
		if(!Q1.empty()) {
			PSI p = Q1.front();
			Q1.pop();
			
			string pstr = p.first;
			int pstep = p.second;
			int idx = pstr.find('.');
			
			for(int i = 0;i < 4;i ++) {
				int tx = idx/3 + dx[i], ty = idx%3 + dy[i];
				int nxt = tx*3+ty;
				if(tx < 0 || tx >= 3 || ty < 0 || ty >= 3 || nxt == idx) continue;
				
				string tmpstr = pstr;
				swap(tmpstr[idx], tmpstr[nxt]);
				
				if(step1[tmpstr]) continue;
				step1[tmpstr] = pstep+1;
				if(step2[tmpstr]) {cout<<step1[tmpstr]+step2[tmpstr]; return 0;}
				Q1.push(PSI(tmpstr, pstep + 1));
			}
		}
		
		if(!Q2.empty()) {
			PSI p = Q2.front();
			Q2.pop();
			
			string pstr = p.first;
			int pstep = p.second;
			int idx = pstr.find('.');
			
			for(int i = 0;i < 4;i ++) {
				int tx = idx/3 + dx[i], ty = idx%3 + dy[i];
				int nxt = tx*3+ty;
				if(tx < 0 || tx >= 3 || ty < 0 || ty >= 3 || nxt == idx) continue;
				
				string tmpstr = pstr;
				swap(tmpstr[idx], tmpstr[nxt]);
				
				if(step2[tmpstr]) continue;
				step2[tmpstr] = pstep+1;
				if(step1[tmpstr]) {cout<<step1[tmpstr]+step2[tmpstr]; return 0;}
				Q2.push(PSI(tmpstr, pstep + 1));
			}
		}
	}
	
	cout<<ans<<endl;

	return 0;
}

代码2:标准做法

// 992s
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<string, int> PSI;

int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
int ans = -1;

queue<PSI> q;

string ss, tt;

map<string, int> vis;

int main()
{
	cin>>ss>>tt;
	
	q.push(PSI(ss, 0));
	vis[ss] = 1;
	
	while(!q.empty()) {
		PSI p = q.front();
		q.pop();
		
		string pstr = p.first;
		int pstep = p.second;
		int idx = pstr.find('.');
		
		if(tt == pstr) {ans = pstep; break;}
		
		for(int i = 0;i < 4;i ++) {
			int tx = idx/3 + dx[i], ty = idx%3 + dy[i];
			int nxt = tx*3+ty;
			if(tx < 0 || tx >= 3 || ty < 0 || ty >= 3 || nxt == idx) continue;
			
			string tmpstr = pstr;
			swap(tmpstr[idx], tmpstr[nxt]);
			
			if(vis[tmpstr] == 1) continue;
			vis[tmpstr] = 1;
			q.push(PSI(tmpstr, pstep + 1));
		}
	}
	
	cout<<ans<<endl;

	return 0;
}

代码3

// 878s
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

struct node{
	int pos, step;
	ll idx;
	node() {}
	node(int p, int s, ll i) {pos = p; step = s; idx = i;}
};

queue<node> q;

int ans = -1, pos;

ll start, des;

string ss, tt;

map<int, int> vis;

int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};

int main()
{
	cin>>ss>>tt;
	for(int i = 0;i < 9;i ++) {
		if(ss[i]=='.') pos = i, start = start*10 + 9;
		else start =  start*10 + (ss[i]-'0');
		des = des*10 + (tt[i]=='.'?9:(tt[i]-'0'));
	}
	
	q.push(node(pos, 0, start));
	while(!q.empty()) {
		node t = q.front();
		q.pop();
		
		int tpos = t.pos;
		ll tidx = t.idx;
		
		if(des == t.idx) {ans = t.step; break;}
		
		for(int i = 0;i < 4;i ++) {
			int tx = (t.pos)/3 + dx[i], ty = (t.pos)%3 + dy[i];
			int nxt = tx*3+ty;
			if(tx < 0 || tx >= 3 || ty < 0 || ty >= 3 || nxt == t.pos) continue;
			
			ll x = pow(10, 8-nxt), y = pow(10, 8-tpos);
			ll high1 = tidx/x, low1 = tidx%x;
			ll num = high1%10;
			ll tmp = (high1/10*10 + 9) * x + low1;
			ll high2 = tmp/y, low2 = tmp%y;
			tmp = (high2/10*10 + num) * y + low2;
//			cout<<nxt<<' '<<tidx<<' '<<high1<<' '<<low1<<' '<<num<<' '<<high2<<' '<<low2<<' '<<tmp<<endl;
			
			if(vis[tmp] == 1) continue;
			vis[tmp] = 1;
			q.push(node(nxt, t.step+1, tmp));
		}
	}
	
	cout<<ans<<endl;

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不牌不改

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

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

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

打赏作者

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

抵扣说明:

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

余额充值