hihocoder offer收割19th 数组重排3 八进制位操作 状态压缩

64 阅读3分钟

hihocoder offer收割19th 数组重排3 hiho1539

哈哈,利用宽度优先搜索,求初态移到有序终态的最少步数。由于最多八个数字,8是个很好的数字,刚好可以用3个bit位存下不大于8的数字,8个不大于的数字可以用24比特位存下(一个int类型就可以存下一个数组的状态了~)。所有状态不可能超过数组长度的阶乘,因为有的状态达不到。比如21,不可能转化为12。

(43210)D 这个序列就可以用 43210 八进制表示,

难就难在状态转化的位操作上。01片段截取重组,

而且ALU进行的是算术移位,左移把高位溢出掉然后右移,高位会出现很多一(按位补),右移挤掉低位再左移补0,这道没啥影响。

对了,用一个数组记录所宽搜过的状态,所有可能的状态都搜过后,还不能达到目标,就无解。

#1539 : 数组重排3

时间限制: 10000ms

单点时限: 1000ms

内存限制: 256MB

    • 描述

    • 给定一个{1..N}的排列A1, A2, ... A``N,每一次操作可以将相邻的两个数一起移动(保持两个数相邻且前后顺序不变)到任意位置。询问至少经过多少次操作,可以使得原序列变为1, 2, ..., N
    • 例如对于54321,把32一起移动到最左端得到32541;再把25一起移动到最右端得到34125;再把12一起移动到最左端得到12345。
    • 输入

    • 第1行:1个正整数 T,表示输入数据的组数
    • 第2..T+1行:每行一个字符串,表示初始排列
    • 对于30%的数据:T = 1, 1 ≤ N ≤ 5
    • 对于100%的数据:1 ≤ T ≤ 5, 1 ≤ N ≤ 8
    • 输出

    • 第1..T行:每行一个整数,第i行表示第i个排列变化为1, 2, ..., N所需要的最少步数。若无可行方案,输出"-1"。
    • 样例输入
    • 2
      54321
      321
      
    • 样例输出
    • 3
      -1
      

我用的八进制操作,debug只能输出中间结果,其中oct是将输出八进制。

#define _CRT_SECURE_NO_WARNINGS  
#include <iostream>  
#include <string>  
#include <queue>  
#include <cstring>
using namespace std;
#define FF 0xFFFFFFFF  
typedef pair<int, int> type;
int state = 0, des, len;
bool vis[16777216];//2^24  
int BFS(int st, int dep) {
	if (st == des) return dep;
	queue<type> q;
	q.push(make_pair(st, dep));
	memset(vis, 0, sizeof vis);
	vis[st] = true;
	while (!q.empty()) {
		type sta = q.front(); q.pop();
		st = sta.first;
		for (int i = 1; i < len; ++i) { //7 6 5 4 3 2 1 0//i是截取位  
			int x = 0x3f << (i - 1) * 3;//6个1  
										//cout << oct << x << endl;  
			x = (x & st) >> (i - 1) * 3;//截取6位  
			long long high = st >> (i + 1) * 3 << (i + 1) * 3;//剩余高位  
			int low = (int)(((long long)st << (32 - (i - 1) * 3) & FF) >> (32 - (i - 1) * 3)); //想要的溢出  
																							   //cout << i << " " << oct << st << " " << oct << x << " " << oct << high << " " << oct << low << endl;//debug  
			for (int in = 0; in <= len; ++in) { //in是插入位  
				if (in == i + 1 || in == i || in == i - 1) continue; //在三个位置插入没意义  
				int stat;
				if (in < i) {
					int lower = (int)(((long long)low << (32 - in * 3) & FF) >> (32 - in * 3));
					//cout << oct << lower << endl;  
					stat = low >> in * 3 << in * 3 + 6; // cout << oct << stat << endl;  
					stat |= high; // cout << oct << stat << endl;  
					stat |= x << in * 3; // cout << oct << stat << endl;  
					stat |= lower;
				}
				else { // in > i 在左边插入  
					int lower = (int)((high << (32 - in * 3) & FF) >> (38 - in * 3));
					//cout << oct << lower << endl;//需要的是逻辑右移  
					stat = high >> in * 3 << in * 3;
					stat |= x << (in - 2) * 3;
					stat |= lower;
					stat |= low;
				}
				//cout << oct << stat << endl;  
				if (!vis[stat]) {
					if (stat == des) return sta.second + 1;
					vis[stat] = true;
					q.push(make_pair(stat, sta.second + 1));
				}
			}
		}
	}
	return -1;
}
int main()
{
	//freopen("D:/coding/Dev/data.in", "r", stdin);  
	ios::sync_with_stdio(false);
	int T;
	cin >> T;
	while (T--) {
		string str;
		cin >> str;
		len = str.length();
		state = des = 0;
		for (int i = 0; i < len; ++i) {
			state |= (str[len - 1 - i] - '1') << (i * 3);
			des |= i << ((len - 1 - i) * 3);
		}
		//cout << oct << state << " " << oct << des << endl;//debug       
		cout << BFS(state, 0) << endl;
	}

	return 0;
}


\

\

\