Acwing 1107 魔板

题目传送门

 

分析:

我们可以把每一种棋盘状态看作一个结点,因为一共就8位数,所以结点数是有限的。也就是说我们可以用这些结点构建一个无向图。

又因为每次转换的“花费”是相同的,即花一次转换机会

因此图上的边权也相等

而题目的问题就可以转化为求边权相等的图上两个点的最短距离

那么就很明显是bfs了

代码:

#include  
using namespace std;

#define fi first
#define se second     

string st = "12345678", dt = "";

//和起点的距离
mapdis;

//手写队列
string q[N * N];

//记录路径 -> 从哪个状态来,以什么方式来的
map >pre;

//三种操作
string op(string now, char c){
	string ans = "";
	if(c == 'A'){
		for(int i = 7; i >= 4; i--) ans += now[i];
		for(int i = 3; i >= 0; i--) ans += now[i];
	}
	else if(c == 'B'){
		ans += now[3];
		for(int i = 0; i < 3; i++) ans += now[i];
		for(int i = 5; i <= 7; i++) ans += now[i];
		ans += now[4];
	}
	else{
		int gs[] = {0, 6, 1, 3, 4, 2, 5, 7};
		for(int i = 0; i < 8; i++) ans += now[gs[i]];
	} 
	return ans;
}


//bfs模板
int bfs(){
	int hh = 0, tt = -1;
	
	q[++tt] = st;
	dis[st] = 0;

	while(hh <= tt){
		auto tp = q[hh++];
		if(tp == dt) return dis[dt];

		string temp = op(tp, 'A');
		if(!dis.count(temp)){
			dis[temp] = dis[tp] + 1;
			q[++tt] = temp;
			pre[temp] = {tp, 'A'};
		} 
		
		temp = op(tp, 'B');
		if(!dis.count(temp)){
			dis[temp] = dis[tp] + 1;
			q[++tt] = temp;
			pre[temp] = {tp, 'B'};
		}
		
		temp = op(tp, 'C');
		if(!dis.count(temp)){
			dis[temp] = dis[tp] + 1;
			q[++tt] = temp;
			pre[temp] = {tp, 'C'};
		}
	}
}

int main(){
	for(int i = 0; i < 8; i++){
		int x;
		scanf("%d", &x);
		dt += x + '0';
	} 
	
	int t = bfs();
	cout << t << endl;
	
	string path = "", now = dt;

	while(now != st){
		path += pre[now].se;
		now = pre[now].fi;
	}
    
	reverse(path.begin(), path.end());
		
	if(t) cout << path << endl;
	
	return 0;
}

如果觉得不错,不妨给个再走呗~

你可能感兴趣的:(算法竞赛,bfs,宽度优先搜索,acwing,模拟)