最小步数模型(bfs

ABC—D - 8 Puzzle on Graph
题意:
有一个空位,利用空位将将矩阵还原
思路:
突然想起来一道典中典的搜索题没有写博客
经典八数码问题
3 ∗ 3 3*3 33 的矩阵转化为字符串表示一种状态
最终状态即为 123456789 123456789 123456789
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
vector <int> v[10];

void work()
{
	cin >> m;
	for(int i = 1; i <= m; ++i){
		int a, b;cin >> a >> b;
		v[a].push_back(b);
		v[b].push_back(a);
	}
	string s = "@999999999";
	for(int i = 1, x; i <= 8; ++i){
		cin >> x;
		s[x] = i + '0';
	}
	queue <string> q;
	unordered_map<string, int> dis;
	q.push(s);
	dis[s] = 0;
	while(!q.empty()){
		string now = q.front();q.pop();
		int pos;
		for(int i = 1; i <= 9; ++i) if(now[i] == '9') pos = i;
		for(auto to : v[pos]){
			string t = now;
			swap(t[to], t[pos]);
			if(dis.count(t)) continue;
			dis[t] = dis[now] + 1;
			q.push(t);
		}
	}
	if(!dis.count("@123456789")) cout << -1;
	else cout << dis["@123456789"];
}


int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

问题 D: 【宽搜入门】魔板
思路:
模拟bfs即可
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
int x;
string st = "12345678";

string A(string t){
	for(int j = 0; j < 4; ++j) swap(t[j], t[7-j]);
	return t;
}
string B(string t){
	char x = t[3];t[3] = t[2]; t[2] = t[1]; t[1] = t[0]; t[0] = x;
	x = t[4];t[4] = t[5], t[5] = t[6], t[6] = t[7]; t[7] = x;
	return t;
}
string C(string t){// now --> t
	string now = t;
	t[1] = now[6]; t[2] = now[1]; t[5] = now[2]; t[6] = now[5];
	return t;
}
void work()
{
	string ed = "";
	ed += x + '0';
	for(int i = 1; i <= 7; ++i){
		cin >> x;ed += (x + '0');
	}
	unordered_map <string, int> dis;
	unordered_map <string, string> pre;
	queue <string> q;
	q.push(st);
	dis[st] = 0;
	while(!q.empty())
	{
		string now = q.front();q.pop();
		for(int i = 0; i < 3; ++i){
			string t = now;
			if(i == 0){// A
				t = A(t);
			}
			else if(i == 1){// B
				t = B(t);
			}
			else {// C
				t = C(t);
			}
			if(!dis.count(t) || dis[t] > dis[now] + 1){
				q.push(t);
				dis[t] = dis[now] + 1;
				pre[t] = now;
			}
		}
	}
	string now = ed;
	string ans;
	while(now != st)
	{
		string t = pre[now];
		// A
		if(A(t) == now){
			ans += "A";
			now = t;
		}
		else if(B(t) == now){
			ans += "B";
			now = t;
		}
		else {
			ans += "C";
			now = t;
		}
	}
	cout << dis[ed] << endl;
	reverse(all(ans));
	cout << ans << endl;
}

int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	while(cin >> x)
	work();
	return 0;
}

46届沈阳 J题
思路:
核心思路:
a , b a,b a,b 转化坐标系
将序列 a a a 转化为 0000 0000 0000,对 b b b 进行相应扭动
假设 a = 2345 , b = 1234 a=2345,b=1234 a=2345,b=1234
2 2 2 向下转两个变成 0 0 0 1 1 1 也向下转两个则变成 9 9 9,即 ( 1 − 2 + 10 ) % 10 (1-2+10)\%10 (12+10)%10
可以推出 b i = ( b i − a i + 10 ) % 10 b_i=(b_i-a_i+10)\%10 bi=(biai+10)%10
b b b 序列每一位转化即可
状态共 1 0 4 10^4 104 种, b f s bfs bfs 预处理即可
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
unordered_map <string, int> dis;
queue <string> q;
vector <string> v;

string change(string now, string d, int k){
	for(int i = 0; i < 4; ++i){
		if(d[i] == '0') continue;
		int x = now[i] - '0', y = d[i] - '0';
		x = (x + k * y + 10) % 10;
		now[i] = x + '0';
	}
	return now;
}
void init(){
	v.push_back("1000");v.push_back("0100");v.push_back("0010");v.push_back("0001");
	v.push_back("1100");v.push_back("0110");v.push_back("0011");v.push_back("1110");
	v.push_back("0111");v.push_back("1111");
	string st = "0000";
	dis[st] = 0;
	q.push(st);
	while(!q.empty())
	{
		string now = q.front();q.pop();
		for(auto d : v){
			string t = change(now, d, 1);
			if(!dis.count(t)) {
				dis[t] = dis[now] + 1;
				q.push(t);
			}
			t = change(now, d, -1);
			if(!dis.count(t)) {
				dis[t] = dis[now] + 1;
				q.push(t);
			}
		}
	}
}
void work()
{
	int x, y;cin >> x >> y;
	string ans = "";
	ans += (y % 10 - x % 10 + 10) % 10 + '0'; x /= 10, y /= 10;
	ans += (y % 10 - x % 10 + 10) % 10 + '0'; x /= 10; y /= 10;
	ans += (y % 10 - x % 10 + 10) % 10 + '0'; x /= 10; y /= 10;
	ans += (y % 10 - x % 10 + 10) % 10 + '0';
	reverse(all(ans));
	cout << dis[ans] << endl;
}

int main()
{
	ios::sync_with_stdio(0);
	init();
	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

172. 立体推箱子
思路:
这种题目难就难在描述状态上
设三元组 ( x , y , l i e ) (x,y,lie) (x,y,lie) 代表一个状态,其中 l i e = 0 lie=0 lie=0 表示长方体立在 ( x , y ) (x,y) (x,y) l i e = 1 lie=1 lie=1 表示长方体横向躺着,左半部分在 ( x , y ) (x,y) (x,y) l i e = 2 lie=2 lie=2 表示长方体纵向躺着,上半部分在 ( x , y ) (x,y) (x,y),并用数组 d i s [ x ] y ] [ l i e ] dis[x]y][lie] dis[x]y][lie] 记录从起点状态到达每个状态的最小步数
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 5e2 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
// 最核心的部分 
const int dx[4] = {0, 0, -1, 1}, dy[4] = {-1, 1, 0, 0};// 作参照 
const int next_x[3][4] = {{0, 0, -2, 1}, {0, 0, -1, 1}, {0, 0, -1, 2}};
const int next_y[3][4] = {{-2, 1, 0, 0}, {-1, 2, 0, 0}, {-1, 1, 0, 0}};
const int next_lie[3][4] = {{1, 1, 2, 2}, {0, 0, 1, 1}, {2, 2, 0, 0}};
// next_x[i][j] 表示 lie = i 时,朝方向 j 滚动 x后的变化情况 

char mp[maxn][maxn];
int dis[maxn][maxn][3];// 状态答案数组
struct node{
	int x, y, lie;
	bool operator==(const node &B)const{
		if(x == B.x && y == B.y && lie == B.lie) return 1;
		return 0;
	}
};
queue <node> q;
node st, ed;

bool check(int x, int y){
	if(x < 1 || y < 1 || x > n || y > m) return 0;
	return 1;
}
bool check(node d){
	if(!(d.x, d.y)) return 0;
	if(mp[d.x][d.y] == '#') return 0;
	if(d.lie == 0 && mp[d.x][d.y] == 'E') return 0;
	if(d.lie == 1 && (mp[d.x][d.y+1] == '#' || !check(d.x, d.y + 1))) return 0;
	if(d.lie == 2 && (mp[d.x+1][d.y] == '#' || !check(d.x + 1, d.y))) return 0;
	return 1;
}
void bfs(){
	while(!q.empty()) q.pop();
	q.push(st);
	dis[st.x][st.y][st.lie] = 0;
	while(!q.empty()){
		node now = q.front();q.pop();
		for(int i = 0; i < 4; ++i){
			node next;
			next.x = now.x + next_x[now.lie][i];
			next.y = now.y + next_y[now.lie][i];
			next.lie = next_lie[now.lie][i];
			if(!check(next)) continue;
			if(dis[next.x][next.y][next.lie] == -1){
				dis[next.x][next.y][next.lie] = dis[now.x][now.y][now.lie] + 1;
				q.push(next);
				if(next == ed) return;
			}
		}
	}
}
void work()
{
	mem(dis, -1);
	for(int i = 1; i <= n; ++i){
		cin >> (mp[i] + 1);
		for(int j = 1; j <= m; ++j){
			if(mp[i][j] == 'O') ed = {i, j, 0};
		}
	}
	for(int i = 1; i <= n; ++i){
		bool f = 0;
		for(int j = 1; j <= m; ++j){
			if(mp[i][j] == 'X'){
				f = 1;
				if(i - 1 >= 1 && mp[i-1][j] == 'X') {
					st = {i-1, j, 2};break;
				}
				if(i + 1 <= n && mp[i+1][j] == 'X') {
					st = {i, j, 2};break;
				}
				if(j - 1 >= 1 && mp[i][j-1] == 'X'){
					st = {i, j - 1, 1};break;
				}
				if(j + 1 <= m && mp[i][j+1] == 'X') {
					st = {i, j, 1};break;
				}
				st = {i, j, 0};break;
			}
		}
		if(f) break;
	}
	bfs();
	int ans = dis[ed.x][ed.y][ed.lie];
	if(ans == -1) cout << "Impossible\n";
	else cout << ans << endl;
}

int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	while(cin >> n >> m && n && m)
	work();
	return 0;
}

173. 矩阵距离
思路:
显然逆向思维,从所有的 1 1 1 开始跑更新最短路就好了
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 1e3 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
const int dx[4] = {0, 0, 1, -1};
const int dy[4] = {1, -1, 0, 0};
char mp[maxn][maxn];
int dis[maxn][maxn];
struct node{
	int x, y, step;
};
queue <node> q;

bool check(int x, int y){
	if(x < 1 || y < 1 || x > n || y > m) return 0;
	return 1;
}
void bfs(){
	while(!q.empty()){
		node now = q.front();q.pop();
		for(int i = 0; i < 4; ++i){
			int x = now.x + dx[i], y = now.y + dy[i];
			if(!check(x, y)) continue;
			if(dis[x][y] > now.step + 1){
				dis[x][y] = now.step + 1;
				q.push({x, y, now.step + 1});
			}
		}
	}
}
void work()
{
	mem(dis, 0x3f);while(q.size()) q.pop();
	cin >> n >> m;
	for(int i = 1; i <= n; ++i) cin >> (mp[i] + 1);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j){
			if(mp[i][j] == '1') q.push({i, j, 0}), dis[i][j] = 0;
		}
	bfs();
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j)
			cout << dis[i][j] << " \n"[j==m];
}

int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值