You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <unordered_set>
|
|
|
|
|
#include <queue>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
typedef unsigned long long ULL; //自动溢出的ULL,计算整数数组的HASH值
|
|
|
|
|
const int B = 17; // 17进制,用于HASH计算,这是大于15的第一个质数
|
|
|
|
|
const int N = 15;
|
|
|
|
|
int n;
|
|
|
|
|
unordered_set<ULL> b; //用于检测一个状态是否已经访问过了
|
|
|
|
|
|
|
|
|
|
struct Node {
|
|
|
|
|
int v[N]; //当前的状态
|
|
|
|
|
int step; //步数
|
|
|
|
|
int f; //估值
|
|
|
|
|
bool operator<(const Node &x) const { //重载小于号
|
|
|
|
|
return x.f < f;
|
|
|
|
|
}
|
|
|
|
|
} x;
|
|
|
|
|
|
|
|
|
|
//优先队列
|
|
|
|
|
priority_queue<Node> q;
|
|
|
|
|
|
|
|
|
|
//检测是否到了目标状态
|
|
|
|
|
bool check(Node x) {
|
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
|
if (x.v[i] != i + 1) return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 计算数组状态的hash值
|
|
|
|
|
ULL getHash(Node x) {
|
|
|
|
|
ULL res = 0;
|
|
|
|
|
for (int i = 0; i < n; i++) res = res * B + x.v[i];
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//估值函数,1次变更,可以最多修改3个后继,现在有res个后继,最少的修改次数是 ⌊res/3⌋=(res+3-1)/3
|
|
|
|
|
int f(Node x) {
|
|
|
|
|
int res = 0;
|
|
|
|
|
for (int i = 1; i < n; i++)
|
|
|
|
|
if (x.v[i] != x.v[i - 1] + 1) res++;
|
|
|
|
|
return (res + 2) / 3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AStar
|
|
|
|
|
int bfs() {
|
|
|
|
|
while (q.size()) {
|
|
|
|
|
Node u = q.top(); //取出当前状态
|
|
|
|
|
q.pop();
|
|
|
|
|
|
|
|
|
|
if (u.f >= 5) return 5; //当前状态无法在5步之内到达终点,返回无结果
|
|
|
|
|
if (check(u)) return u.step; //如果第一次获取到了一个成功的状态,返回当前步数
|
|
|
|
|
|
|
|
|
|
for (int len = 1; len < n; len++) { //枚举长度
|
|
|
|
|
for (int st = 0; st + len - 1 < n; st++) { //枚举起始坐标
|
|
|
|
|
for (int ed = st + len; ed < n; ed++) {
|
|
|
|
|
//抄出来
|
|
|
|
|
memcpy(x.v, u.v, sizeof u.v);
|
|
|
|
|
|
|
|
|
|
//三次翻转,子串对调
|
|
|
|
|
reverse(x.v + st, x.v + st + len);
|
|
|
|
|
reverse(x.v + st + len, x.v + ed + 1);
|
|
|
|
|
reverse(x.v + st, x.v + ed + 1);
|
|
|
|
|
|
|
|
|
|
//如果此状态已经进过优先队列,那么放弃掉
|
|
|
|
|
ULL hash = getHash(x);
|
|
|
|
|
if (b.count(hash)) continue;
|
|
|
|
|
//记录使用过
|
|
|
|
|
b.insert(hash);
|
|
|
|
|
|
|
|
|
|
//修改步数
|
|
|
|
|
x.step = u.step + 1;
|
|
|
|
|
//计算h值 h = g + f
|
|
|
|
|
x.f = x.step + f(x);
|
|
|
|
|
//入队列
|
|
|
|
|
q.push(x);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AC 279 ms
|
|
|
|
|
int main() {
|
|
|
|
|
int T;
|
|
|
|
|
scanf("%d", &T);
|
|
|
|
|
while (T--) {
|
|
|
|
|
//清空Hash表
|
|
|
|
|
b.clear();
|
|
|
|
|
//清空优先队列,清空优先队列的一个小技巧
|
|
|
|
|
q = {};
|
|
|
|
|
|
|
|
|
|
scanf("%d", &n);
|
|
|
|
|
|
|
|
|
|
//初始状态入队列
|
|
|
|
|
for (int i = 0; i < n; i++) scanf("%d", &x.v[i]); //当前的数组状态
|
|
|
|
|
x.step = 0; //原始状态,步数为0
|
|
|
|
|
x.f = f(x); //到达终点的最少步数估值
|
|
|
|
|
|
|
|
|
|
q.push(x); //对象入队列
|
|
|
|
|
b.insert(getHash(x)); //记录此状态已使用
|
|
|
|
|
|
|
|
|
|
int res = bfs(); // A*寻路
|
|
|
|
|
|
|
|
|
|
if (res >= 5)
|
|
|
|
|
puts("5 or more");
|
|
|
|
|
else
|
|
|
|
|
printf("%d\n", res);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|