[HPUOJ] 1152: 棋盘变换 [搜索]

来源:互联网 发布:php markdown 编辑:程序博客网 时间:2024/05/16 15:43

题目描述

给定一个4*4的01棋盘,1代表棋子,0代表空格,棋子1每次可以移动到相邻上下左右四个位置的空格。然后再给定你目标棋盘,问你最少在多少步能把当前棋盘变成目标棋盘状态。

输入

第一行输入一个整数T,代表有T组测试数据。接下来给出只有0和1的4*4的当前棋盘和4*4的目标棋盘,中间有一个空行。

输出

输出一个整数表示最小的步数,若不能到达输出-1。

样例输入

1
0001
0011
1100
1111

1011
1101
0000
1101

样例输出

8

思路

港巨巨提供的思路:

把棋盘是4×4 的,有216 种状态,所以可以分别用数字表示出每个状态。用数字表示出了状态就可以对状态进行记忆了,从起始位置BFS跑一遍即可,复杂度O(216164)

注: 222=4194304
link: http://acm.hpu.edu.cn/problem.php?id=1152

#pragma GCC optimize ("O2")#include<stdio.h>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<queue>#include<map>using namespace std;int s,t,dp[1<<17];const int ox[]={0,0,1,-1};const int oy[]={1,-1,0,0};int get(int &x){    x=0;int z,cnt=0;    for(int i=0,z;i<16;++i){        scanf("%1d",&z);        if(z) ++cnt,x+=1<<i;    }    return cnt;}bool ex(int v,int x,int y){return (v>>(x*4+y))&1;}/*void print(int n){    for(int i=0;i<16;++i){        if(i!=0&&i%4==0) putchar('\n');        printf("%d",n>>i&1);    }    putchar('\n');}*/void work(){    memset(dp,-1,sizeof(dp));    queue<int> que;    que.push(s);    dp[s]=0;    while(!que.empty()){        int V=que.front();que.pop();        if(V==t) break;    //  printf("[%d] ----\n",dp[V]);    //  print(V);        for(int i=0;i<16;++i){            if(V>>i&1){                int X=i/4,Y=i%4;                for(int j=0;j<4;++j){                    int x=X+ox[j];                    int y=Y+oy[j];                    if(0<=x&&x<4&&0<=y&&y<4&&!ex(V,x,y)){                        int v=~(1<<i) & V | 1<<(4*x+y);                        if(dp[v]!=-1) continue;                        dp[v]=dp[V]+1;                        que.push(v);                    }                }            }        }    }    while(!que.empty()) que.pop();    printf("%d\n",dp[t]);}int main(){    int T,z;    scanf("%d",&T);    while(T--){        if(get(s)!=get(t)) puts("-1");        else work();    }    return 0;}
原创粉丝点击