标签:难题 const int Luogu1379 tot aim vis 数码 include
discription:
9宫格, 其中有一个空位(0), 每次操作可以将一个与空位临接的数与空位交换, 问最少需要多少次达到目标123804765(实际上是12345678顺序围了一圈中间放0~)(像不像21世纪10年代手机里的拼图小游戏?)
solution:
先手打一个临接表存储可能的状态转移:(用二维数组加 dx[],dy[]
也差不多)
const int [9][5] = {
{2,1,3},
{3,0,2,4},
{2,1,5},
{3,0,4,6},
{4,1,3,5,7},
{3,2,4,8},
{2,3,7},
{3,4,6,8},
{2,5,7}
};
起点输入明确, 目标状态唯一已知, 因此考虑双向bfs
.比较容易实现的一种方法是两个点轮流扩展, 并且用hash避免重复.这里的hash_map
有一点技巧性:
把aim的导出节点分成一类vis=1, 把a(input)的导出节点分成一类vis=2.
双起点的强大在于:\(2^{\frac{k}{2}+1} = o(2^k)\)
code:
#include<cstdio>
#include<unordered_map>
#include<queue>
using namespace std;
unordered_map<int, int> vis;
unordered_map<int, int> step;
const int aim = 123804765;
int a;
const int t[9][5] = {
{2,1,3},
{3,0,2,4},
{2,1,5},
{3,0,4,6},
{4,1,3,5,7},
{3,2,4,8},
{2,3,7},
{3,4,6,8},
{2,5,7}
};
inline void swap(int& a, int& b) {
int t = a;
a = b, b = t;
}
inline int read() {
int tot = 0;
for (int i = 0; i < 9; ++i)
tot = (tot << 1) + (tot << 3) + getchar() - '0';
return tot;
}
inline int _hash(int* a) {
int tot = 0;
for (int i = 8; i >= 0; --i)
tot = (tot << 1) + (tot << 3) + a[i];
return tot;
}
inline int rehash(int a, int *arr) {
int pos;
for (int i = 0; i < 9; ++i) {
arr[i] = a % 10;
a /= 10;
if (!arr[i])pos = i;
}
return pos;
}
inline void bfs() {
if (a == aim) {
puts("0");
return;
}
int tmp[9];
queue<int> q;
q.push(a);
q.push(aim);
vis[a] = 1, vis[aim] = 2;
step[a] = 0, step[aim] = 1;
int cur, last;
while (!q.empty()) {
last = q.front();
q.pop();
int x0 = rehash(last, tmp);
for (int i = 1; i <= t[x0][0]; ++i) {
int xn = t[x0][i];
swap(tmp[xn], tmp[x0]);
cur = _hash(tmp);
if (vis[cur] == vis[last]) {
swap(tmp[xn], tmp[x0]);
continue;
}
if (vis[cur] + vis[last] == 3) {
printf("%d\n", step[cur] + step[last]);
return;
}
vis[cur] = vis[last];
step[cur] = step[last] + 1;
q.push(cur);
swap(tmp[xn], tmp[x0]);
}
}
}
int main() {
a = read();
bfs();
}
标签:难题,const,int,Luogu1379,tot,aim,vis,数码,include 来源: https://www.cnblogs.com/dwt2021/p/14472432.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。