搜索_BFS_行列变换问题

版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/84517810

问题描述:   

       给定两个4\times 4方格阵列组成的图形A和图形B,每个方格的颜色为黑色或白色,如下图所示。行列变换问题的每一步变换可以交换任意2行或2列方格的颜色,或者将某行或某列颠倒。上述每次变换算作一步。试设计一个算法,计算最少需要多少步,才能将图形A变换为图形B。

                                                        

解题思路:

       (1)使用先进先出队列式分支限界法

       (2)将每个格局使用一个int变量表示

       (3)将各种变换转换为位运算

下面给出基于上述思路的代码:

//行列变换问题
#include <iostream>
#include <cstring> 
#include <queue>
using namespace std;
const int MAX = 5;
int beg, tar, cnt[1 << MAX * MAX];
//返回x >= 0行y >= 0对应的位, 最低位对应第0位 
int p(int x, int y){
	return 4 * x + y;
}
//交换sta的第pos1位和第pos2位
void swapD(int &sta, int pos1, int pos2){
	int a = sta >> pos1 & 1, b = sta >> pos2 & 1;
	if(b) sta |= 1 << pos1; else sta &= ~(1 << pos1);
	if(a) sta |= 1 << pos2; else sta &= ~(1 << pos2);	
} 
//交换sta的第i行和第j行
void swapR(int &sta, int i, int j){
	for(int k = 0; k < 4; ++k) swapD(sta, p(i, k), p(j, k));
} 
//交换sta的第i列和第j列
void swapC(int &sta, int i, int j){
	for(int k = 0; k < 4; ++k) swapD(sta, p(k, i), p(k, j));
} 
//将sta的第i行颠倒 
void reR(int &sta, int i){
	swapD(sta, p(i, 0), p(i, 3)), swapD(sta, p(i, 1), p(i, 2));
}
//将sta的第i列颠倒
void reC(int &sta, int i){
	swapD(sta, p(0, i), p(3, i)), swapD(sta, p(1, i), p(2, i));	
} 
int main(){
	//输入起始状态
	for(int i = 0, t; i < 4; ++i)
		for(int j = 0; j < 4; ++j){
			cin >> t; if(t) beg ^= 1 << p(i, j);
		}
	//输入目标状态
	for(int i = 0, t; i < 4; ++i)
		for(int j = 0; j < 4; ++j){
			cin >> t; if(t) tar ^= 1 << p(i, j);
		}
				
	//执行BFS 
	memset(cnt, 0, sizeof(cnt)); queue<int> qu; 
	cnt[beg] = 1, qu.push(beg);
	while(!qu.empty()){
		int t = qu.front(); qu.pop(); 
		//行交换
		for(int i = 0; i < 4; ++i)
			for(int j = i + 1; j < 4; ++j){
				int tmp = t; swapR(tmp, i, j); 
				if(!cnt[tmp] || cnt[t] + 1 < cnt[tmp]) 
					cnt[tmp] = cnt[t] + 1, qu.push(tmp);
			} 
		//列交换 
		for(int i = 0; i < 4; ++i)
			for(int j = i + 1; j < 4; ++j){
				int tmp = t; swapC(tmp, i, j); 
				if(!cnt[tmp] || cnt[t] + 1 < cnt[tmp]) 
					cnt[tmp] = cnt[t] + 1, qu.push(tmp);
			} 
		//行颠倒
		for(int i = 0; i < 4; ++i){	
			int tmp = t; reR(tmp, i);
			if(!cnt[tmp] || cnt[t] + 1 < cnt[tmp]) 
				cnt[tmp] = cnt[t] + 1, qu.push(tmp);	
		} 
		//列颠倒 
		for(int i = 0; i < 4; ++i){	
			int tmp = t; reC(tmp, i);
			if(!cnt[tmp] || cnt[t] + 1 < cnt[tmp]) 
				cnt[tmp] = cnt[t] + 1, qu.push(tmp);	
		} 
	}
	cout << cnt[tar] - 1 << endl;
	return 0;
} 

运行截图:

                                                   

猜你喜欢

转载自blog.csdn.net/solider98/article/details/84517810