[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('\n');
}

 

posted @ 2020-07-15 19:28  月落乌啼算钱  阅读(129)  评论(0编辑  收藏  举报