广搜——状态压缩

先看题:

小 C 做了一个拼图游戏,大家来破解它吧。

游戏规则:每次可以移动相邻的两张图片,所有图片都在指定的位置上,游戏完成。

简化问题,每次输入一个 3 × 3 3\times 3 3×3 的矩阵,表示要拼的图。

分析

可以发现此题搜索树特别庞大,所以不进行状态判重是不行的。

所以我们可以开一个 9 9 9 维的 bool 数组来进行判重,但这样子空间复杂度约为 1GB,如果你家电脑能开的下也行

很明显如果只对一个状态判重,那多开的其他空间就是浪费,所以考虑将一个 3 × 3 3\times 3 3×3 的矩阵压成一个 9 9 9 位十进制整数,如将矩阵:

123
456
789

压成 123456789 123456789 123456789,但是普通的数组开不到 1 0 9 10^9 109 的所以可以用 map 或哈希实现。

而广搜时只需将整数化为矩阵进行操作,再将矩阵压成整数放入队列。

代码

实现时有些技巧,具体看代码。

#include 
#define int long long

using namespace std;

const int N = 15, mod = 1000003;//哈希模数设为质数效率会高些
int dx[] = {0, 1, 0}, dy[] = {0, 0, 1};
vector <int> nbr[mod + 5];//哈希数组

bool find(int x){//查找有没有出现过
	int P = x % mod;
	for(int i = 0; i < nbr[P].size(); i ++){
		if(nbr[P][i] == x){
			return true;
		}
	}
	return false;
}
void insert(int x){//将 x 插入散列表
	int P = x % mod;
	nbr[P].push_back(x);
}
int get_now(int a[N][N]){//得到当前矩阵对应的整数
	int tmp = 0;
	for(int i = 1; i <= 3; i ++){
		for(int j = 1; j <= 3; j ++){
			tmp = tmp * 10 + a[i][j];
		}
	}
	return tmp;
}

signed main(){
	int t = 0;
	for(int i = 1; i <= 3; i ++){
		for(int j = 1; j <= 3; j ++){
			char c;
			cin >> c;
			t = t * 10 + (c - '0' + 1);//将输入的矩阵压成整数
		}
	}
	
	if(t == 123456789){
		cout << "0";
		return 0;
	}
	
	queue < pair <int, int> > q;
	insert(t);
	q.push(make_pair(t, 0));
	
	while(!q.empty()){
		int cur = q.front().first, step = q.front().second;
		q.pop();
		if(cur == 12345689){//判断是否达到目标状态
			cout << step;
			return 0;
		}
		int a[N][N];
		for(int i = 3; i >= 1; i --){//将整数化为矩阵
			for(int j = 3; j >= 1; j --){
				a[i][j] = cur % 10;
				cur /= 10;
			}
		}
		for(int i = 1; i <= 3; i ++){
			for(int j = 1; j <= 3; j ++){
				for(int k = 1; k <= 2; k ++){//一个点只需和下、左方位的点互换就行
					int nx = i + dx[k], ny = j + dy[k];
					if(nx < 1 || nx > 3 || ny < 1 || ny > 3){
						continue;
					}
					swap(a[i][j], a[nx][ny]);//交换位置
					int o = get_now(a);//将矩阵化为整数
					if(!find(o)){//状态判重
						q.push(make_pair(o, step + 1));
						insert(o);
						if(o == 123456789){//由于搜索树很大在这里提前输出可以减少超多时间
							cout << step + 1;
							return 0;
						}
					}
					swap(a[i][j], a[nx][ny]);//将矩阵恢复原样
				}
			}
		}
	}
	return 0;
}

你可能感兴趣的:(数据结构,bfs,c++)