2019 深信服 下棋(DFS+回溯)

連接:https://www.nowcoder.com/questionTerminal/a0feb0696e2043a5b3b0779fa861b64a?f=discussion
來源:牛客網

ios

8x8的棋盤上,布有黑白兩色棋子,白子先下,當白子下N手後,棋盤上最多有可能留下多少顆白子?

下法規則:
1.每次落子後,以該棋子爲中心的8個方向(米字形的8條直線),若是有同色棋子,
且兩個同色棋子之間連續排列着若干個異色棋子,無空白及同色棋子。則,此次落子能夠把這些夾在中間的異色棋子所有翻色(即黑變白,白變黑)。

2. 黑白子交錯落子。

3. 若是一個位置上有棋子,不能繼續在該位置上落子;

4. 若是一個位置上落子後,不能翻對手的棋子,則該位置不能落子;

1表示黑色,2表示白色,0表示空白未落子
白棋落子後,棋盤變化狀況以下所示:
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 1 2 0 0 0    =>   0 0 0 1 2 0 0 0 
0 0 0 2 1 0 0 0         0 0 0 2 2 2 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 

0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 1 2 0 0 0    =>   0 0 0 1 2 0 0 0 
0 0 1 2 1 2 0 0         0 0 1 2 1 1 1 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 

 

輸入描述:
第一行爲白子須要走的步數

接下來8行數據,指明棋盤上的棋子狀態,其中1爲黑子,2爲白子,0爲空位置


輸出描述:
白子下完N手後,棋盤上的白子個數的最大可能。
示例1

輸入

1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 1 2 0 0 0
0 0 0 2 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

輸出

4

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#define ll long long
using namespace std;
typedef pair<int,int> p;


int mp[8][8];
int dir[8][2]={-1,0,1,0,0,-1,0,1,-1,-1,-1,1,1,-1,1,1};//上,下,左,右,左上,右上,左下,右下
int n,ans;

int find_sum(int x,int y,int dx,int dy,int nwcolor,int others)
{
    int cnt=1;
    x+=dx; y+=dy;
    while(x>=0&&x<8&&y>=0&&y<8)
    {
        if(mp[x][y]==nwcolor)
            return cnt;
        if(mp[x][y]!=others)
            return 0;
        x+=dx;
        y+=dy;
        cnt++;
    }
    return 0;
}
void dfs(int step)
{
    if(step==n)
    {
        int cnt=0;
        for(int i=0; i<8; i++)
        {
            for(int j=0; j<8; j++)
                if(mp[i][j]==2) cnt++;
        }
        ans=max(ans,cnt);
        return;
    }
    int nw,lst;
    vector<p> g;//保存要改變的棋子位置
    if(step%2==0)
    {
        nw=2;
        lst=1;
    }
    else
    {
        nw=1;
        lst=2;
    }
    for(int i=0; i<8; i++)
    {
        for(int j=0; j<8; j++)
        {
            if(mp[i][j]==0)
            {
                int flag=0;//回溯標記
                for(int k=0; k<8; k++)
                {
                    int cnt=find_sum(i,j,dir[k][0],dir[k][1],nw,lst);//從當前位置[i,j]沿當前方向能夠改變多少個棋子
                    if(cnt>1)
                    {
                        int x=i,y=j;
                        for(int ii=0; ii<cnt; ii++)
                        {
                            mp[x][y]=nw;
                            g.push_back(make_pair(x,y));//保存要更新的棋子位置
                            x+=dir[k][0];
                            y+=dir[k][1];
                        }
                        flag=1;
                    }
                }
                if(flag)
                {
                    dfs(step+1);
                    for(int ii=0; ii<g.size(); ii++)//回溯
                    {
                        mp[g[ii].first][g[ii].second]=lst;
                    }
                    mp[i][j]=0;
                    g.clear();
                }
            }
        }
    }
}

int main()
{
    scanf("%d",&n);
    n=2*n-1;
    for(int i=0; i<8; i++)
    {
        for(int j=0; j<8; j++)
        {
            scanf("%d",&mp[i][j]);
        }
    }
    ans=0;
    dfs(0);
    printf("%d\n",ans);
    return 0;
}
相關文章
相關標籤/搜索