BUAA(2021春)五子棋危险判断——简单的搜索算法

48 篇文章 154 订阅

看前须知

要点介绍和简要声明.

第二次上机题汇总

五子棋危险判断——简单的搜索算法.

字符串替换(新)——朴素的查找和替换.

加密文件——分步骤一步一步有逻辑性完成.

通讯录整理——结构体一级排序.

小型图书管理系统.

题目内容

问题描述

已知两人分别执白棋和黑棋在一个围棋棋盘上下五子棋,若同一颜色的棋子在同一条横行、纵行或斜线上连成5个棋子,则执该颜色棋子的人获胜。编写程序读入某一时刻下棋的状态,并判断是否有人即将获胜,即:同一颜色的棋子在同一条横行、纵列或斜线上连成4个棋子,且该4个棋子的两端至少有一端为空位置。
输入的棋盘大小是19×19,用数字0表示空位置(即没有棋子),用数字1表示该位置下了一白色棋子,用数字2表示该位置下了一黑色棋子。假设同一颜色的棋子在同一条横行、纵列或斜线上连成的棋子个数不会超过4个,并且最多有一人连成线的棋子个数为4

输入形式

从控制台输入用来表示棋盘状态的数字0、1或2;每行输入19个数字,各数字之间以一个空格分隔,每行最后一个数字后没有空格;共输入19行表示棋盘状态的数字。

输出形式

若有人即将获胜,则先输出即将获胜人的棋子颜色(1表示白色棋子,2表示黑色棋子),然后输出英文冒号:,最后输出连成4个棋子连线的起始位置(棋盘横行自上往下、纵列自左往右从1开始计数,横行最小的棋子在棋盘上的横行数和纵列数作为连线的起始位置,若在同一行上,则纵列数最小的棋子位置作为起始位置,两数字之间以一个英文逗号,作为分隔符)。
若没有人获胜,则输出英文字符串:No。
无论输出什么结果,最后都要有回车换行符。

样例

【输入样例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 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 2 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 2 0 1 1 2 0 0 0 0 0 0 0
0 0 0 0 0 2 1 1 1 1 2 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 2 1 2 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1 0 2 2 0 0 0 0 0 0 0 0
0 0 0 0 0 2 0 1 0 0 2 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 0
0 0 0 0 0 0 0 0 0 0 0 0 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 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】

1:9,8

【输入样例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 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 0 0 0 0
0 0 0 0 0 0 0 1 2 2 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 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 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 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

【输出样例2】

No

样例说明

在输入的样例1中,执白棋(数字1表示)的人即将获胜,连成4个棋子且有一端为空的起始位置在第9行第8列,所以输出1:9,8。
在输入的样例2中,还没有同一颜色的棋子连成4个,所以无人即将获胜,直接输出No。

题解

易错点和难点

这道题就是在考察简单的搜索算法。根据题意,在一般情况我们需要对一个棋子的右,右下,下,左下四个方向进行搜索,一旦有一个是满足的立刻break出来。但是要特殊处理棋子在最左边和左右边的情况,因为在此刻只需要对三个方向甚至只有两个方向进行搜索,否则会因为数组越界而WA。

参考代码

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>
#define right 3       //宏定义方向 
#define right_down 4
#define down 5
#define left_down 6
int q[30][30];  //棋盘 
int i=0,j=0;
int flag=0;     //判断标志 
void search(int q[][30]);  //搜索函数 
void move(int m,int num);  //搜索方向 
int main()
{	
	for(i=1;i<=19;i++)
	{
		for(j=1;j<=19;j++)
		{
			scanf("%d",&q[i][j]);//输入当前棋盘 
		}
	}
	i=1,j=1;
	search(q); //开始搜索 
	
	if(flag==1)
	{
		printf("%d:%d,%d",flag,i,j);
	}
	else if(flag==2)
	{
		printf("%d:%d,%d",flag,i,j);
	}
	else
	{
		printf("No");
	}
	return 0;
}
void move(int m,int num)
{
	if(m==3)  //right
	{
		if(q[i][j+1]==num && q[i][j+2]==num && q[i][j+3]==num && (q[i][j+4]==0 || q[i][j-1]==0)) //0表示有可以下棋的位置 
		{
			flag=num;
		}
	}
	else if(m==4)  //right_down
	{
		if(q[i+1][j+1]==num && q[i+2][j+2]==num && q[i+3][j+3]==num && (q[i+4][j+4]==0 || q[i-1][j-1]==0))//0表示有可以下棋的位置 
		{
			flag=num;
		}
	}
	else if(m==5) //down
	{
		if(q[i+1][j]==num && q[i+2][j]==num && q[i+3][j]==num && (q[i+4][j]==0 || q[i-1][j]==0))//0表示有可以下棋的位置 
		{
			flag=num;
		}
	}
	else if(m==6)  //left_down
	{
		if(q[i+1][j-1]==num && q[i+2][j-2]==num && q[i+3][j-3]==num && (q[i+4][j-4]==0 || q[i-1][j+1]==0))//0表示有可以下棋的位置 
		{
			flag=num;
		}
	}
}
void search(int q[][30])
{
	for(i=1;i<=19;i++)
	{
		for(j=1;j<=19;j++)
		{
			if(q[i][j]==1)
			{
				if(j==1)  //如果在最左边 
				{
					move(right,1);
					move(right_down,1);
					move(down,1);
					if(flag!=0) break;
				}
				else if(j==19)  //如果在最右边 
				{
					move(left_down,1);
					move(down,1);
					if(flag!=0) break;
				}
				else //其余情况 
				{
					move(right,1);
					move(right_down,1);
					move(down,1);
					move(left_down,1);
					if(flag!=0) break;
				}
			}
			if(q[i][j]==2) //与重复上面步骤 
			{
				if(j==1)
				{
					move(right,2);
					move(right_down,2);
					move(down,2);
					if(flag!=0) break;
				}
				else if(j==19)
				{
					move(left_down,2);
					move(down,2);
					if(flag!=0) break;
				}
				else
				{
					move(right,2);
					move(right_down,2);
					move(down,2);
					move(left_down,2);
					if(flag!=0) break;
				}
			}
		}
		if(flag!=0) break;
	}
}

补充测试的数据

输入
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 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 1 2 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 2 2 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 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 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 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

输出

2:1,19
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值