P4289 [HAOI2008]移动玩具

题目描述

在一个4*4的方框内摆放了若干个相同的玩具,某人想将这些玩具重新摆放成为他心中理想的状态,规定移动时只能将玩具向上下左右四个方向移动,并且移动的位置不能有玩具,请你用最少的移动次数将初始的玩具状态移动到某人心中的目标状态。

输入输出格式

输入格式:

前4行表示玩具的初始状态,每行4个数字1或0,1表示方格中放置了玩具,0表示没有放置玩具。接着是一个空行。接下来4行表示玩具的目标状态,每行4个数字1或0,意义同上。

输出格式:

一个整数,所需要的最少移动次数。

输入输出样例

输入样例#1: 
1111
0000
1110
0010 

1010
0101
1010
0101
输出样例#1: 
4

Solution:

  本题比较水,但是我调得快心态炸裂了。(因为变量名的问题,弄错了好几个变量,搞得一直以为手打队列有错,唉~太菜了~!)

  从某一状态转移到另一状态,且给定了转移方法,那么不难想到,一般直接广搜就$OK$了。

  关键如何判重和记录状态,此时由于每个状态是一个$16$位$0/1$字符串,很自然想到了状态压缩:用$1$到$2^{16}=65536$来记录每个状态,爆搜就$AC$了。至于如何转移就直接模拟好了!(本人较蠢,方法比较繁琐,话说手推了一波转移过程,~滑稽~)

代码:

#include<bits/stdc++.h>
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=65560;
int st,ed,op[20],opt,mp[N],ans;
int dx[17][4]={
    0,0,0,0, 
    1,4,0,0, 
    -1,1,4,0, 
    -1,1,4,0, 
    -1,4,0,0, 
    -4,4,1,0, 
    -1,1,4,-4, 
    -1,1,4,-4,
    -4,4,-1,0,
    -4,4,1,0,
    -1,1,4,-4,
    -1,1,4,-4,
    -4,4,-1,0,
    -4,1,0,0,
    -4,-1,1,0,
    -4,-1,1,0,
    -4,-1,0,0
};
queue<int>q;
char s;
bool vis[N];
int main(){
    ios::sync_with_stdio(0);
    For(i,1,16)cin>>s,st=(st<<1)+s-'0';
    For(i,1,16)cin>>s,ed=(ed<<1)+s-'0';
    q.push(st);vis[st]=1;
    while(!q.empty()){
        int u=q.front();q.pop();int p=u;
        if(u==ed)break;
        For(i,1,16){op[17-i]=p%2,p>>=1;}
        For(i,1,16) For(j,0,3)
        if(dx[i][j]!=0){
            if(op[i+dx[i][j]]!=op[i]){
                swap(op[i+dx[i][j]],op[i]);
                opt=0;
                For(k,1,16) opt=(opt<<1)+op[k];
                if(!vis[opt]){
                    vis[opt]=1,q.push(opt),mp[opt]=mp[u]+1;
                }
                swap(op[i+dx[i][j]],op[i]);
            }
        }
    }
    cout<<mp[ed];
    return 0;
}
原文地址:https://www.cnblogs.com/five20/p/9043026.html