codevs2743 黑白棋游戏

题目描述 Description

题目传送门

黑白棋游戏的棋盘由4×4方格阵列构成。棋盘的每一方格中放有1枚棋子,共有8枚白棋子和8枚黑棋子。这16枚棋子的每一种放置方案都构成一个游戏状态。在棋盘上拥有1条公共边的2个方格称为相邻方格。一个方格最多可有4个相邻方格。在玩黑白棋游戏时,每一步可将任何2个相邻方格中棋子互换位置。对于给定的初始游戏状态和目标游戏状态,编程计算从初始游戏状态变化到目标游戏状态的最短着棋序列。

输入描述 Input Description

输入共有8行。前四行是初始游戏状态,后四行是目标游戏状态。每行4个数分别表示该行放置的棋子颜色。“0”表示白棋;“1”表示黑棋。

输出描述 Output Description

输出的第一行是着棋步数n。接下来n行,每行4个数分别表示该步交换棋子的两个相邻方格的位置。例如,abcd表示将棋盘上(a,b)处的棋子与(c,d)处的棋子换位。

样例输入 Sample Input
1111
0000
1110
0010
1010
0101
1010
0101
样例输出 Sample Output
4
1222
1424
3242
4344

题解

虽然打着钻石的名号却不过是个暴力,但是这么水的暴力我居然写了那么久!!!!

题目分类是状态压缩,但是我觉得是BFS时的状态压缩,并不是一个DP。16个格子压成2^16不大,才65536,int就够了。然后搜索相邻的不同颜色格子,注意标程应该是枚举格子然后先向下再向右搜的,不这样写会WA2个点。因为可以用65536内的数表示一种状态,先不管输出过程,先打一个找最小步数的BFS,然后用pre[i] 表示i情况的上一步是哪个,step[i] 将从pre[i] —-> i 的转移方式压成一个4位的int存一下,输出时用stack倒个序即可

代码

#include<queue>
#include<stack>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i) for(int i=1;i<=4;i++)
using namespace std;
const int maxn=100000+10;
const int dx[]={1,0};
const int dy[]={0,1};
struct Node{
    int cur,d,pre,step;
    Node(int cur,int d,int p,int s):cur(cur),d(d),pre(p),step(s){}
};

int pre[maxn],step[maxn];
int press(int map[5][5])
{
    int ret=0;
    rep(i) rep(j) ret=ret*2+map[i][j];
    return ret;
}
void unpress(int x,int map[5][5])
{
    for(int i=4;i>=1;i--)
      for(int j=4;j>=1;j--)
      {
        map[i][j]=x%2;x/=2;
      }
    return ;
}

int m[5][5],vis[maxn];
bool inside(int x,int y){return x>=1&&x<=4&&y>=1&&y<=4;}
void BFS(int s,int t)
{
    queue<Node>q;
    q.push(Node(s,0,s,0));
    while(!q.empty())
    {
        Node k=q.front();q.pop();
        if(vis[k.cur]) continue;
        vis[k.cur]=1;
        pre[k.cur]=k.pre;
        step[k.cur]=k.step;
        if(k.cur==t) 
        {
            stack<int>st;
            printf("%d\n",k.d);
            for(int i=t;i!=s;i=pre[i])st.push(step[i]);
            while(!st.empty()) printf("%d\n",st.top()),st.pop();
            return;
        }
        int tmp[5][5];
        unpress(k.cur,tmp);
        rep(x) rep(y)
            for(int i=0;i<2;i++)
            {
                int nx=x+dx[i],ny=y+dy[i];
                if(inside(nx,ny)&&tmp[nx][ny]!=tmp[x][y])
                {
                    swap(tmp[nx][ny],tmp[x][y]);
                    int tt=press(tmp);
                    q.push(Node(tt,k.d+1,k.cur,x*1000+y*100+nx*10+ny));
                     swap(tmp[nx][ny],tmp[x][y]);
                }   
            }
    }
}

int main()
{
    rep(i) rep(j) scanf("%01d",&m[i][j]);
    int s=press(m);
    rep(i) rep(j) scanf("%01d",&m[i][j]);
    int t=press(m);
    BFS(s,t);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值