传送门:下棋
8x8的棋盘上,布有黑白两色棋子,白子先下,当白子下N手后,棋盘上最多有可能留下多少颗白子?
下法规则:
1.每次落子后,以该棋子为中心的8个方向(米字形的8条直线),如果有同色棋子,
且两个同色棋子之间连续排列着若干个异色棋子,无空白及同色棋子。则,这次落子可以把这些夹在中间的异色棋子全部翻色(即黑变白,白变黑)。
-
黑白子交错落子。
-
如果一个位置上有棋子,不能继续在该位置上落子;
-
如果一个位置上落子后,不能翻对手的棋子,则该位置不能落子;
1表示黑色,2表示白色,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
输出例子1:
4
解题思路:
因为是一个 8 * 8 的矩阵,所以我们完全可以 dfs 遍历所有的状态,找最大值。
要注意的是如果一个位置上落子后,不能翻对手的棋子,则该位置不能落子
AC代码:
#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;
//printf("\n");
for(int i=0; i<8; i++)
{
for(int j=0; j<8; j++)
{
//printf("%d ",mp[i][j]);
if(mp[i][j]==2) cnt++;
}
//printf("\n");
}
//printf("\n");
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);
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;
}