1004 四子连棋(思路重要)

1004 四子连棋
 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 黄金 Gold
 
题目描述 Description
在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,
任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑
白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局。

●	○	●	 
○	●	○	●
●	○	●	○
○	●	○	 
 
输入描述 Input Description

从文件中读入一个4*4的初始棋局,黑棋子用B表示,白棋子用W表示,空格地带用O表示。

输出描述 Output Description

用最少的步数移动到目标棋局的步数。

样例输入 Sample Input
BWBO
WBWB
BWBW
WBWO

样例输出 Sample Output
5

数据范围及提示 Data Size & Hint
hi

**************代码有点冗长了。。但是思路最重要,不要看别人的题解,费神费力。
************自己理解了按自己想法先做着吧(确定自己思路后管它对不对做了再说) 

#include<iostream>
#include<string.h>
#include<cstdlib>
#include<cstdio>

using namespace std;

typedef struct
{
	int map[16];          // B -> 1 , W -> 2
	int pre;                //上一次走的棋 
}QUEUE;

QUEUE q[1000000];
int head = 0,tail = 1,step = 1;
int dx[4] = {-1,1,0,0} , dy[4] = {0,0,-1,1};
bool v[1000];

int check_status(int *nstatus)            //判重:棋子代号*位置(也不知是不是真的靠谱,但是过了) 
{
	int cnt = 0;
	for(int i = 0; i < 16; i++)
		cnt += nstatus[i]*(i+1);
	return cnt;
}

bool check_reachgoal(int *a)              //有错,见评论,谢谢!
{
	if( (a[0] == a[1] && a[1] == a[2] && a[2] == a[3]) ||
	    (a[4] == a[5] && a[5] == a[6] && a[6] == a[7]) ||
	    (a[8] == a[9] && a[9] == a[10] && a[10] == a[11]) ||
	    (a[12] == a[13] && a[13] == a[14] && a[14] == a[15])  ) { cout<<"1 a!"<<endl; return true;}          //横行 

	if( (a[0] == a[4] && a[4] == a[8] && a[8] == a[12]) ||
	    (a[1] == a[5] && a[5] == a[9] && a[9] == a[13]) ||
	    (a[2] == a[6] && a[6] == a[10] && a[10] == a[14]) ||
	    (a[3] == a[7] && a[7] == a[11] && a[11] == a[15])  ) { cout<<"2 a!"<<endl; return true; }             //竖行 

	if( (a[0] == a[5] && a[5] == a[10] && a[10] == a[15]) ||
	    (a[3] == a[6] && a[6] == a[9] && a[9] == a[12]) ) { cout<<"2 a!"<<endl; return true; }          //斜行 
	
	return false;                          //注意return false否则会return true; 
}

void bfs()
{
	int qi,i,j,r = 0,oldtail;
	int ox[2],oy[2],ol[2],nx,ny,nl;
	QUEUE nstatus;
	//第一次走棋特殊考虑 
	for(i = 0; i < 16; i++)                   //找空格 
		if(!q[0].map[i])
		{
			ox[r] = i/4 , oy[r] = i%4 , ol[r] = i;
			r++;
		}
	for(i = 0; i < 2; i++)                //第0,1个空格分别产生情况 
	{
		for(j = 0; j < 4; j++)
		{
			nx = ox[i] + dx[j] , ny = oy[i] + dy[j];
			nl = nx*4+ny;
			if(nx >= 0 && ny >= 0 && nx < 4 && ny < 4 && q[0].map[nl])
			{
				memcpy(nstatus.map,q[0].map,sizeof(nstatus.map));           //产生新状态 
				nstatus.pre =  nstatus.map[nl];
				nstatus.map[nl] = 0;
				nstatus.map[ol[i]] = q[0].map[nl];
/*              test : check_reachgoal少了最后的return true; 
				for(int ti = 0; ti < 16; ti++)
				    cout<<nstatus.map[ti];
				cout<<endl;
*/
				if(check_reachgoal(nstatus.map))
				{
//					cout<<"no"<<endl;
					cout<<step<<endl;
					exit(0);
				}
				q[tail++] = nstatus;
				v[check_status(nstatus.map)] = 1;
			}
		}
	}
	head++ , step++;
	while(head < tail)
	{
		oldtail = tail;
		for(qi = head; qi < oldtail; qi++)
		{
			r = 0;
			for(i = 0; i < 16; i++)           //找空格 
			{
				if(!q[qi].map[i])
				{
					ox[r] = i/4 , oy[r] = i%4 , ol[r] = i;
					r++;
				}
			}
			for(i = 0; i < 2; i++)               //第0,1个空格分别产生情况
			{
				for(j = 0; j < 4; j++)
				{
					nx = ox[i] + dx[j] , ny = oy[i] + dy[j];
					nl = nx*4+ny;
					if(nx >= 0 && ny >= 0 && nx < 4 && ny < 4 && q[qi].map[nl] != q[qi].pre && q[qi].map[nl])
					{
						memcpy(nstatus.map,q[qi].map,sizeof(nstatus.map));
						nstatus.pre = nstatus.map[nl];
						nstatus.map[nl] = 0;
						nstatus.map[ol[i]] = q[qi].map[nl];
						if(check_reachgoal(nstatus.map))
						{
							cout<<step<<endl;
							exit(0);
						}
						if(!v[check_status(nstatus.map)]) q[tail++] = nstatus;
					}
				}
			}
		}
		head = oldtail;
		step++;
	}
}

int main()
{
    memset(v,0,sizeof(v));
	char a;
	int i,r = 0;
	for(i = 0; i < 16; i++)
	{
		cin>>a;
		if(a == 'B') q[0].map[i] = 1;
		else if(a == 'W') q[0].map[i] = 2;
		else q[0].map[i] = 0;
	}
	bfs();
	return 0;
}
*************************************************************************仅供吐槽
根据提供的引用内容,华为OD机试题目中的五子棋迷是指张兵和王武这位工作之余经常切磋棋艺的人。在下棋过程中,张兵此时轮到他思考,他需要考虑一条线上的棋子分布,用数组表示为-1 0 1 1 1 0 1 0 1 -1。其中,-1代表白子,0代表空位,1代表黑子。数组的长度L满足1 < L < 40,且L为奇数。 根据该题目的要求,我们需要定义个指针L和R,它们的范围就是要求的连棋范围。在该范围内,必须要包含一个0用于落子,并且范围内的其余棋子必须是下棋者对应的颜色(即第一行输入的颜色)。 那么L和R范围内需要满足三个条件:首先,范围内必须要包含一个0用于落子,并且只能有一个0;其次,范围内的其余棋子必须是下棋者对应的颜色;最后,L和R范围的长度不能超过5。 综上所述,华为OD机试的五子棋迷题目主要涉及了对棋盘上一条线的棋子分布进行判断,并根据一定的条件来确定落子的范围。这道题目主要考察对数组的处理和条件判断的能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [华为OD机试 - 五子棋迷(Java & JS & Python)](https://blog.csdn.net/qfc_128220/article/details/130766999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值