2024第15届蓝桥杯省赛C/C++大学A组第二题B题解:五子棋对弈

目录

        问题描述:

        方法一:dfs,剪枝


问题描述:

        “在五子棋的对弈中,友谊的小船说翻就翻? 不!对小蓝和小桥来说,五子棋不仅是棋盘上的较量,更是心与心之间的沟通。这两位挚友秉承着 “ 友谊第一,比赛第二” 的宗旨,决定在一块 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;
}

        我做这道题的时候,只枚举了第一个格子放白棋的所有情况,忘了枚举第一个格子放黑棋的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值