前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Luogu P1225 黑白棋游戏 题解

Luogu P1225 黑白棋游戏 题解

作者头像
yzxoi
发布2022-09-19 13:12:00
6070
发布2022-09-19 13:12:00
举报
文章被收录于专栏:OI

Luogu P1225 黑白棋游戏 题解

Preface

题目链接

这题真的恶心,状压写错了调半天。。。

Description

给定一个 4\times 4 的棋盘,每一格放一个棋子,共有 8 个黑棋,8 个白棋。每次可以交换相邻两个格子的棋子,问最少要多少步才能从初始状态到达最终状态。并且需要输出交换方法。

Solution

由于棋盘十分小(只有 4\times 4 ),所以考虑食用 bfs

这道题主要问题是状态如何考虑。

由于只有黑棋和白棋,所以很自然的就想到了状压的思想。

我们可以考虑将整个棋盘直接状压成一个 16 位二进制数,再进行 bfs 转移。

代码语言:javascript
复制
for(int i=0;i<4;i++)
    for(int j=0;j<4;j++){
        char c=gc();W(c!='0'&&c!='1') c=gc();
        S=(c&15)<<i*4+j;//直接状压
    }

那么在 bfs 的时候,只需要根据这个状压方法提取出需要交换的两位,并且暴力交换后再压回去即可。

代码语言:javascript
复制
I int v(int p,int x,int y){return p>>x*4+y&1;}//获取该状态下的该位置权值
I int swp(int p,int x,int y,int xx,int yy){
    int v1=v(p,x,y),v2=v(p,xx,yy);//获取这两位的权值
    p&=((1<<16)-1)^1<<x*4+y,p&=((1<<16)-1)^1<<xx*4+yy,//把该状态下的这两位清空
    p=v2<<x*4+y,p=v1<<xx*4+yy;//赋值
    return p;
}

另外,在 bfs 的过程中,记录一下父亲及路径即可,最后递归输出。

Code

代码语言:javascript
复制
// Problem: P1225 黑白棋游戏
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1225
// Memory Limit: 125 MB
// Time Limit: 1000 ms

// Auther: yzxoi
// Site: yzxoi.top 

#include<cstdio>
#include<queue>
#include<cstring>
#define W while
#define I inline
#define LL long long
#define gc getchar
#define ig(c) ('0'<=(c)&&(c)<='9')
#define pc(c) putchar((c))
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
I int read(){int x=0,f=1;char c=gc();W(!ig(c)) f=c=='-'?-1:f,c=gc();W(ig(c)) x=(x<<3)+(x<<1)+(c&15),c=gc();return x*f;}
I void write(int x){x<0&&(pc('-'),x=-x,0),x<10?(pc(x+'0'),0):(write(x/10),pc(x%10+'0'),0);}
const int N=114514;
const int dx[]={0,0,1,-1},
          dy[]={1,-1,0,0};
int S,T,dis[N],vis[N],pre[N];
struct node{int x,y,xx,yy;}pp[N];
std::queue<int> q;
I int v(int p,int x,int y){return p>>x*4+y&1;}
I int swp(int p,int x,int y,int xx,int yy){int v1=v(p,x,y),v2=v(p,xx,yy);p&=((1<<16)-1)^1<<x*4+y,p&=((1<<16)-1)^1<<xx*4+yy,p=v2<<x*4+y,p=v1<<xx*4+yy;return p;}
I void print(int p){
    for(int i=0;i<4;i++){
        for(int j=0;j<4;j++){
            printf("%d ",p>>i*4+j&1);
        }
        pc('\n');
    }
}
I void bfs(int x){
    W(!q.empty()) q.pop();
    q.push(x);
    memset(dis,63,sizeof(dis));
    dis[x]=0;
    W(!q.empty()){
        int u=q.front();q.pop();
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                for(int k=0;k<4;k++){
                    int xx=i+dx[k],yy=j+dy[k],p;
                    if(xx>=0&&xx<4&&yy>=0&&yy<4&&v(u,i,j)^v(u,xx,yy)) dis[p=swp(u,i,j,xx,yy)]>dis[u]+1&&(dis[p]=dis[u]+1,pre[p]=u,pp[p]=(node){i,j,xx,yy},!vis[p]&&(vis[p]=1,q.push(p),0),0);
                }
    }
}
I void printpre(int x){
    if(pre[x]) printpre(pre[x]);
    else return ;
    write(pp[x].x+1),write(pp[x].y+1),write(pp[x].xx+1),write(pp[x].yy+1),pc('\n');
}
int main(){
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++){
            char c=gc();W(c!='0'&&c!='1') c=gc();
            S=(c&15)<<i*4+j;
        }
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++){
            char c=gc();W(c!='0'&&c!='1') c=gc();
            T=(c&15)<<i*4+j;
        }
    bfs(S);
    write(dis[T]),pc('\n');
    printpre(T);
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-10-27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Luogu P1225 黑白棋游戏 题解
    • Preface
      • Description
        • Solution
          • Code
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档