题解 [HAOI2008] 移动玩具
题意
题目链接:传送门
题目大意是给两个\(4*4\)的\(01\)矩阵\(A,B\),求至少对矩阵\(A\)中任意元素进行上下左右移动多少次后能使得\(A=B\)
Solution
碎碎念:不知道当时考试是不是时限给的\(100ms\)(应该是吧)
先考虑暴力做法,自然地想到把矩阵变成\(01\)串状态压缩,\(2^{16}=65536\),可以直接用哈希判重,bfs即可。
注意一下模拟移动的细节和边界情况。
然后这个暴力有可能会T掉(其实卡一卡好像并不会)
还是来考虑一下优化好了。。。。
显然可以\(A*\),估价函数设计为\(status\ xor\ target\),其中\(status\)表示当前状态,\(target\)表示目标状态,即求目前有多少位与目标状态不同,容易证明其正确性。
某谷上一共跑了约\(20ms\),\(LOJ\)上莫名跑的比暴力还慢。。。。
后来做了几个测试,发现暴力好像跑的的确很快。。。省选为什么考爆搜(大雾
附代码:
#include
#define rep(a,b,c) for (int a=b;a<=c;a++)
#define per(a,b,c) for (int a=b;a>=c;a--)
using namespace std;
typedef long long ll;
template inline void read(T &x){
ll f = 1;x = 0;char ch = getchar();
while (!isdigit(ch)){if (ch == '-')f = -1;ch = getchar();}
while (isdigit(ch)){x = (x << 1)+(x << 3)+(ch ^ 48);ch = getchar();}
x *= f;
}
struct node
{
int eva,step,sta;
bool operator < (const node &X) const
{
return eva==X.eva?step>X.step:eva>X.eva;
}
}Now;
int targt,init;
bool vis[65536];
priority_queue Q;
inline void _get(int &x)
{
char c;
rep(i,1,16)
{
cin>>c;
x=(x<<1)+c-'0';
}
}
inline int evaluate(int sta)
{
int dif=sta^targt;
int res=0;
while(dif)
{
res+=dif&1;
dif>>=1;
}
return res;
}
int u[4]={4,-4,1,-1};
inline int move(int sta,int pos,int opt)
{
int x=(sta>>pos)&1,y=(sta>>(pos+u[opt]))&1;
if(y==0)sta=sta&(~(1<>i)&1))continue;
rep(j,0,3)
{
if(j==0&&i>11||j==1&&i<4||j==2&&i%4==3||j==3&&i%4==0)continue;
int x=move(fi.sta,i,j);
if(!vis[x])
{
vis[x]=1;
Now.step=fi.step+1;
Now.sta=x;
Now.eva=Now.step+evaluate(x);
if(Now.eva==Now.step)
{
printf("%d",Now.step);
return;
}
Q.push(Now);
}
}
}
}
}
int main()
{
_get(init),_get(targt);
if(init==targt)
{
cout<<0<