目录
问题描述:
“在五子棋的对弈中,友谊的小船说翻就翻?
”
不!对小蓝和小桥来说,五子棋不仅是棋盘上的较量,更是心与心之间的沟通。这两位挚友秉承着 “
友谊第一,比赛第二”
的宗旨,决定在一块
5
×
5
的棋盘上,用黑白两色的棋子来决出胜负。但他们又都不忍心让对方失落,于是决定用一场和棋(平局)
作为彼此友谊的见证。
比赛遵循以下规则:
1.
棋盘规模
:比赛在一个
5
×
5
的方格棋盘上进行,共有
25
个格子供下棋使用。
2.
棋子类型
:两种棋子,黑棋与白棋,代表双方。小蓝持白棋,小桥持黑棋。
3.
先手规则
:白棋(小蓝)具有先手优势,即在棋盘空白时率先落子(下棋)。
4.
轮流落子
:玩家们交替在棋盘上放置各自的棋子,每次仅放置一枚。
5.
胜利条件
:率先在横线、竖线或斜线上形成连续的五个同色棋子的一方获胜。
6.
平局条件
:当所有
25
个棋盘格都被下满棋子,而未决出胜负时,游戏以平局告终。
在这一设定下,小蓝和小桥想知道,有多少种不同的棋局情况(终局不同看成不同情况,终局相同而落子顺序不同看成同一种情况),既确保棋盘下满又保证比赛结果为平局。
答案提交:
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。答案为3126376。
方法一:dfs,剪枝
根据题意,枚举出所有可能的棋盘情况,判断是否有一方获胜,统计平局的总数即可。可以通过dfs的方式枚举,从棋盘的第1格枚举到第25格,每格依次放置黑棋白棋,在函数参数中填写白棋和黑棋的个数,如果白棋超过13个或者黑棋超过12个则停止搜索。在每个位置,都判断当前四个方向(横向,纵向,对角)是否有连成一线的情况,如果有则停止搜索。一次搜索停止后撤销对棋盘的更改。详情请看代码及注释。
#include<bits/stdc++.h>
using namespace std;
int a[10][10];//表示棋盘
int ans=0;
void dfs(int n1,int n2,int id,int c)//白棋个数,黑棋个数,当前格子序号,当前格子颜色
{
//如果白棋超过13个,黑棋超过12个,则停止搜索
if(n1>=14||n2>=13||id>=25) return ;
int x=id/5,y=id%5;//将序号转为坐标
a[x][y]=c;//将当前格放置对应棋子
//判断当前横行是否连成一线,如果y<4,则此行未摆满5个棋子不须判断
if(y==4)
{
bool flag=0;
for(int i=0;i<=4;i++)
{
if(a[x][i]!=a[x][0]) flag=1;
}
if(flag==0) return ;
}
//判断当前纵行是否连成一线,如果x<4,则此列未摆满5个棋子不须判断
if(x==4)
{
bool flag=0;
for(int i=0;i<=4;i++)
{
if(a[i][y]!=a[0][y]) flag=1;
}
if(flag==0) return ;
}
//判断对角线是否连成一线,当id=20时,第一条对角线才被填满
if(id==20)
{
bool flag=0;
for(int i=0;i<=4;i++)
{
if(a[i][4-i]!=a[0][4]) flag=1;
}
if(flag==0) return ;
}
//判断对角线是否连成一线,当id=24时,第二条对角线才被填满
if(id==24)
{
bool flag=0;
for(int i=0;i<=4;i++)
{
if(a[i][i]!=a[0][0]) flag=1;
}
if(flag==0) return ;
}
//函数执行到这一行,说明没有连成一线的情况,若已经枚举完最后一个棋子,说明是平局
if(id>=24)
{
ans++;
return ;
}
dfs(n1+1,n2,id+1,1);//将下一个格子放白棋
x=(id+1)/5,y=(id+1)%5;
a[x][y]=0;//撤销白棋
dfs(n1,n2+1,id+1,2);//将下一个格子放黑棋
x=(id+1)/5,y=(id+1)%5;
a[x][y]=0;//撤销黑棋
}
int main()
{
dfs(1,0,0,1);//枚举第一个格子放白棋的所有情况
dfs(0,1,0,2);//枚举第一个格子放黑棋的所有情况
cout<<ans;
return 0;
}
我做这道题的时候,只枚举了第一个格子放白棋的所有情况,忘了枚举第一个格子放黑棋的情况。