【XDU ACM周训】 Week 4 - T 聪明的打字员(BFS+状态压缩)

题目大意:

输入区有六个数字和一个光标(光标开始时位于第一个数),使用以下六种操作将其变为目标数字,求最少操作数:

1.Swap0:将光标所在数字和第一个数交换

2.Swap1:将光标所在数字和最后一个数交换

3.Up:给光标所在数字+1

4.Down:给光标所在数字-1

5.Left:光标左移

6.Right:光标右移

分析:

这道题做得很失败,一开始想当然的剪枝,认为2-5的四个数字只要和目标数字不同,就没必要移动光标,居然还A了。。数据太水。后来看一个dalao博客给出的一组数据,000159 000519,最小操作数是8,即交换19、51、95,光标是可以移动的嘛!

正解:

将操作分为两类,只有Up/Down可以改变数字的值,剩下四种操作实际上只能改变给定数字的相对位置。把六个数字的位置、光标位置和已访问的数字(只有光标访问过的数字才能用Up/Down改变)作为状态,一遍BFS搜出所有可能的组合,再加上与每一位目标数字之差的绝对值的和(即Up/Down次数)就是答案了。

注意:光标的访问状态只有十种,第一位一定会被访问,而且只有Right和Swap1可以访问未访问过的位置


代码:

#include <iostream>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;

bool vis[6][6][6][6][6][6][6][10] = {0};//0-5分别对应输入区6个数字的位置,6表示下标位置,7表示下标访问状态
bool list[10][6] = {{1,0,0,0,0,0},//只有Right或Swap1可以访问未访问过的位置,所以只有10种访问状态
					{1,0,0,0,0,1},
					{1,1,0,0,0,0},
					{1,1,0,0,0,1},
    				{1,1,1,0,0,0},
    				{1,1,1,0,0,1},
    				{1,1,1,1,0,0},
    				{1,1,1,1,0,1},
    				{1,1,1,1,1,0},
    				{1,1,1,1,1,1}};
					
struct node{//分别是 下标位置,访问状态,步数,6个数字的位置
	 int pos; int state; int d; vector<int> n;
};

int main(){
	int i, j, a[6] = {0}, b[6] = {0}, ts, min = 0x7FFFFFFF, r;
	string sa, sb;
	cin >> sa >> sb;
	for (i = sa.size()-1, j = 5; i >= 0; i--, j--) a[j] = sa[i]-'0';
	for (i = sb.size()-1, j = 5; i >= 0; i--, j--) b[j] = sb[i]-'0';
	
	queue<node> q;
	int init[6] = {0, 1, 2, 3, 4, 5};
	vector<int> t;
	q.push((node){0, 0, 0, vector<int>(init, init+6)});
	vis[0][1][2][3][4][5][0][0] = 1;
	while (!q.empty()){
		node f = q.front();
		q.pop();
		//根据当前状态计算所需Up/Down次数
		r = f.d;
		for (i = 0; i < 6; i++){
			if (list[f.state][i]) r += fabs(a[f.n[i]]-b[i]);
			else if (a[f.n[i]] != b[i]){
				r = 0x7FFFFFFF;
				break;
			}
		}
		if (r < min) min = r;
		//Swap0
		t = f.n;
		t[0] = f.n[f.pos];//交换
		t[f.pos] = f.n[0];
		if (!vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos][f.state]){
			q.push((node){f.pos, f.state, f.d+1, t});
			vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos][f.state] = 1;
		}
		//Swap1
		t = f.n;
		t[5] = f.n[f.pos];//交换
		t[f.pos] = f.n[5];
		if (f.state % 2 == 0) ts = f.state+1;//访问到最后一个数
		else ts = f.state;
		if (!vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos][ts]){
			q.push((node){f.pos, ts, f.d+1, t});
			vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos][ts] = 1;
		}
		//Left
		t = f.n;
		if (f.pos > 0 && !vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos-1][f.state]){
			q.push((node){f.pos-1, f.state, f.d+1, f.n});
			vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos-1][f.state] = 1;
		}
		//Right
		t = f.n;
		if (f.state <= 6) ts = f.state+2;//访问到下一个数
		else ts = 9;
		if (f.pos < 5 && !vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos+1][ts]){
			q.push((node){f.pos+1, ts, f.d+1, f.n});
			vis[t[0]][t[1]][t[2]][t[3]][t[4]][t[5]][f.pos+1][ts] = 1;
		}
	}
	cout << min;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wangyucong1999310/article/details/80538998