wikioi-天梯-普及一等-bfs-1004:四子连棋

在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局。

 
 

 

从文件中读入一个4*4的初始棋局,黑棋子用B表示,白棋子用W表示,空格地带用O表示。

用最少的步数移动到目标棋局的步数。

BWBO
WBWB
BWBW
WBWO

5

类型:图论  难度:2

题意:一个4*4的棋盘,上面有7黑7白和两个空格,每次移动中,可以将黑白移动到上下左右的空格处,黑白交替走,任一方可先走。问至少走几步,可以使同样颜色的棋子在一列(横竖斜均可)

分析:比较明显的广搜题。即维护一个队列,初始化时,先将当前棋盘入队,每次取队头的状态并出队,然后遍历从这个状态的所有下一个状态并入队,若下个状态满足要求,输出最少的步数。因为使用队列,所以先入队的状态的步数一定小于后入队的,所以第一次找到的满足要求的状态即为最小步数。

几点注意:

1、需要维护一个hash表,记录已经遍历的状态,每次有新状态时在表中找是否出现过

2、由于有2个空格,所以一个状态最多会产生8个新状态。

3、注意黑白棋走,我就是没注意到这点结果错了好几次。我用另一个队列记录每个状态的移动的棋子加以判定。

代码:

#include<iostream>
#include<cstring>
#include<string>
#include<map>
#include<queue>
#include<cstdio>
using namespace std;

string m;
map<string,int> in;
queue<string> st;
queue<char> pre;
int dir[4][2] = {{-1,0},{1,0},{0,1},{0,-1}};

bool isfinish(string a)
{
    int cnt1,cnt2;
    for(int i=0; i<4; i++)
    {
        cnt1 = cnt2 = 1;
        for(int j=1; j<4; j++)
        {
            if(a[i*4+j]==a[i*4]) cnt1++;
            if(a[j*4+i]==a[i]) cnt2++;
        }
        if(cnt1==4 || cnt2==4) return 1;
    }
    cnt1 = cnt2 = 1;
    for(int i=1; i<4; i++)
    {
        if(a[i*5]==a[0]) cnt1++;
        if(a[i*3+3]==a[3]) cnt2++;
    }
    if(cnt1==4 || cnt2==4) return 1;
    return 0;
}

void print(char c,string a)
{
    for(int i=0; i<4; i++)
        cout<<c<<a.substr(i*4,4)<<endl;
}

int main()
{
    for(int i=0; i<4; i++)
    {
        string tmp;
        cin>>tmp;
        m += tmp;
    }
    st.push(m);
    pre.push(0);
    in[m] = 1;
    
    int ans = 0;
    while(!st.empty())
    {
        string now = st.front();
        int pren = pre.front();
        st.pop();
        pre.pop();
        //cout<<in[now]<<endl;
        //print(' ',now);
        if(isfinish(now))
        {
            ans = in[now]-1;
            break;
        }
        for(int i=0; i<16;i++)
        {
            if(now[i]=='O')
            {
                int x = i/4;
                int y = i%4;
                int nx,ny;
                for(int j=0; j<4; j++)
                {
                    nx = x+dir[j][0];
                    ny = y+dir[j][1];
                    if(nx<0 || nx>3 || ny<0 || ny>3)
                        continue;
                    if(now[nx*4+ny] == pren)
                        continue;
                    string next = now;
                    next[i] = next[nx*4+ny];
                    next[nx*4+ny] = 'O';
                    if(in[next]) continue;
                    in[next] = in[now]+1;
                    st.push(next);
                    pre.push(next[i]);
                    
                    //cout<<"\t"<<in[next]<<endl;
                    //print('\t',next);
                    //getchar();
                }
            }
        }
    }
    cout<<ans<<endl;
}


 

你可能感兴趣的:(图论,bfs,WIKIOI,天梯)