[HAOI2008]移动玩具
题目大意:
给你两个4*4的01矩阵A、B,要求你从矩阵A中将‘1‘移动若干步(移动即与相邻的‘0‘交换位置),变换为B,输出最小步数.
基本思路:
本题数据较小,固定为4*4,第一时间想到状压(2^16),用状压代替hash比较容易.由于要求最小步数,bfs扫描到B矩阵即可输出答案,复杂度远小于dfs.
code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define R register
#define next exnt
#define debug puts("mlg")
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void write(ll x);
inline void writesp(ll x);
inline void writeln(ll x);
ll ans[65536],n,goal;
bool d[5][5];
inline ll calc(bool M[5][5]){
ll sum=0;
for(R ll i=1;i<=16;i++) if(M[(i-1)/4+1][(i-1)%4+1]) sum+=1<<i-1;
return sum;
}
queue<ll>q;
inline void Bfs(ll now){
ll To;
q.push(now);
while(q.size()){
now=q.front();q.pop();
if(now==goal){
writeln(ans[now]);exit(0);
}
for(R ll i=1;i<=16;i++) d[(i-1)/4+1][(i-1)%4+1]=(now&(1<<i-1));
for(R ll i=1;i<=4;i++){
for(R ll j=1;j<=4;j++){
if(d[i][j]){
if(i-1>0&&!d[i-1][j]){
swap(d[i-1][j],d[i][j]);
To=calc(d);
if(ans[To]>ans[now]+1){
ans[To]=ans[now]+1;
q.push(To);
}
swap(d[i-1][j],d[i][j]);
}
if(i+1<5&&!d[i+1][j]){
swap(d[i+1][j],d[i][j]);
To=calc(d);
if(ans[To]>ans[now]+1){
ans[To]=ans[now]+1;
q.push(To);
}
swap(d[i+1][j],d[i][j]);
}
if(j-1>0&&!d[i][j-1]){
swap(d[i][j-1],d[i][j]);
To=calc(d);
if(ans[To]>ans[now]+1){
ans[To]=ans[now]+1;
q.push(To);
}
swap(d[i][j-1],d[i][j]);
}
if(j+1<5&&!d[i][j+1]){
swap(d[i][j+1],d[i][j]);
To=calc(d);
if(ans[To]>ans[now]+1){
ans[To]=ans[now]+1;
q.push(To);
}
swap(d[i][j+1],d[i][j]);
}
}
}
}
}
}
int main(){
for(R ll i=1,x;i<=16;i++){
char c=getchar();
while(c!=‘0‘&&c!=‘1‘) c=getchar();
x=c-‘0‘;
if(x) n+=1<<i-1;
}
memset(ans,0x3f,sizeof ans);
for(R ll i=1,x;i<=16;i++){
char c=getchar();
while(c!=‘0‘&&c!=‘1‘) c=getchar();
x=c-‘0‘;
if(x) goal+=1<<i-1;
}
ans[n]=0;
Bfs(n);
}
inline ll read(){
ll x=0,t=1;char ch=getchar();
while(ch<‘0‘||ch>‘9‘){
if(ch==‘-‘) t=-1;
ch=getchar();
}
while(ch>=‘0‘&&ch<=‘9‘){
x=x*10+ch-‘0‘;
ch=getchar();
}
return x*t;
}
inline void write(ll x){
if(x<0){putchar(‘-‘);x=-x;}
if(x<=9){putchar(x+‘0‘);return;}
write(x/10);putchar(x%10+‘0‘);
}
inline void writesp(ll x){
write(x);putchar(‘ ‘);
}
inline void writeln(ll x){
write(x);putchar(‘
‘);
}

![[HAOI2008]移动玩具
[编程语言教程]](https://www.zixueka.com/wp-content/uploads/2024/02/1706717705-b5b4447a05810d7.jpg)
