搜索 HOJ 1736 A Game on the Chessboard

A Game on the Chessboard

My Tags   (Edit)
  Source : CEOI 1999
  Time limit : 1 sec   Memory limit : 32 M

Submitted : 26, Accepted : 20

On the chessboard of size 4x4 there are 8 white and 8 black stones, i.e. one stone on each field. Such a configuration of stones is called a game position. Two stones are adjacent if they are on fields with a common side (i.e. they are adjacent in either horizontal or vertical direction but not diagonal). It means that each stone has at most 4 neighbours. The only legal move in our game is exchanging any two adjacent stones. Your task is to find the shortest sequence of moves transforming a given starting game position into a given final game position.

Input

The starting game position is described in the first 4 lines of input. There are 4 symbols in each line, which define the colour of each stone in the row from the left to the right. The lines describe the rows of the chessboard from the top to the bottom. Symbol `0' means a white stone and symbol `1' a black one. There is no space symbol separating the symbols in the line. The fifth line is empty. The next 4 following lines describe the final game position in the same way.

Output

The first line of output contains the number of the moves. The following lines describe the sequence of moves during the game. One line describes one move and it contains 4 positive integers R_1 C_1 R_2 C_2 separated by single spaces. These are the coordinates of the adjacent fields for the move, i.e. fields [R_1,C_1] and [R_2,C_2], where R_1 (or R_2) is the number of the row and C_1 (or C_2) is the number of the column. The rows on the chessboard are numbered from 1 (top row) to 4 (bottom row) and the columns are numbered from 1 (the leftmost column) to 4 (the rightmost one) as well (i.e. the coordinates of the left upper field are [1,1]). If there are multiple shortest sequences of moves transforming the starting position to the final position, you can output any one of them.

Sample Input

1111
0000
1110
0010

1010
0101
1010
0101

Sample Output

4
1 2 2 2
1 4 2 4
3 2 4 2
4 3 4 4

题意:有一个棋盘,上面放了黑色和白色两种颜色的棋子,一次只能交换相邻两个位置的棋子,然后给出起始状态和目的状态,问最少能经过多少步到达,并且给出具体的操作。

思路:宽搜就行了,如果单向能过就单向搜就行了,如果不过就双向。由于只有16个位置,所以状态数为2^16,完全可以把棋盘看成一个int进行判重。然后记录步骤的时候我们用16bit表示棋盘状态,用8bit表示操作,因为操作是R1,C1,R2,C2 其中它们都是[1,4]那么两位就能表示一个数了,所以4个数字只需要8bit,我们用低8位表示操作,高16位表示棋盘状态。具体的操作可以看代码。

代码:
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string.h>
#include<queue>
using namespace std;
#define LL long long

int d[1<<16|1] , s , t , now;
int pre[1<<16|1];
int Move[2][4] = { { -1 , 0 , 1 , 0 } , { 0 , 1 , 0 , -1 } };
char buffer[10];

int row(int st)
{
        return st / 4;
}

int column(int st)
{
        return st % 4;
}

int to_loc(int r,int c)
{
        return r*4+c;
}

bool inRange(int r,int c)
{
        if (r < 0 || r >= 4 || c <0 || c >= 4) return false;
        return true;
}

void init()
{
        memset(pre,-1,sizeof(pre));
        memset(d,-1,sizeof(d));
}

void input()
{
        s = t = 0;
        int base = 1;
        for (int j = 0 ; j < 4 ; ++j) 
        {
                if (buffer[j]=='1') s += base;
                base *= 2;
        }
        for (int i = 1 ; i < 4 ; ++i)
        {
                scanf("%s",buffer);
                for (int j = 0 ; j < 4 ; ++j)
                {
                        if (buffer[j]=='1') s += base;
                        base *= 2;
                }
        }
        base = 1;
        for (int i = 0 ; i < 4 ; ++i)
        {
                scanf("%s",buffer);
                for (int j = 0 ; j < 4 ; ++j)
                {
                        if (buffer[j]=='1') t += base;
                        base *= 2;
                }
        }
}

void output(int cur)
{
        if (cur==s) return;
        output(pre[cur]>>8);
        printf("%d %d %d %d\n",(pre[cur]>>6&3)+1,(pre[cur]>>4&3)+1,(pre[cur]>>2&3)+1,(pre[cur]&3)+1);
}

void solve()
{
        queue<int> q;
        q.push(s);
        d[s] = 0;
        while (q.size())
        {
                int st = q.front(); q.pop();
                if (st==t) break;
                for (int r = 0 ; r < 4 ; ++r)
                {
                        for (int c = 0 ; c < 4 ; ++c)
                        {
                                for (int i = 0 ; i < 4 ; ++i)
                                {
                                        now = st;
                                        int rr = r+Move[0][i];
                                        int cc = c+Move[1][i];
                                        if (!inRange(rr,cc)) continue;
                                        int k1 = to_loc(r,c);
                                        int k2 = to_loc(rr,cc);
                                        int tmp = ((1<<k2&now)>>k2<<k1)+((1<<k1&now)>>k1<<k2);
                                        now -= (1<<k1&now)+(1<<k2&now);
                                        now += tmp;
                                        if (d[now]==-1)
                                        {
                                                d[now] = d[st]+1;
                                                q.push(now);
                                                pre[now] = (st<<8)+(r<<6)+(c<<4)+(rr<<2)+cc;
                                        }
                                }
                        }
                }
        }
        printf("%d\n",d[t]);
        output(t);
}

int main()
{
        while (scanf("%s",buffer)==1)
        {
                init();
                input();
                solve();
        }
}


 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值