luogu2346 四子连棋

题目大意

  在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局。求用最少的步数移动到目标棋局的步数。

 

  总体思路很简单,Bfs即可,只是需要注意以下几点:

  • memcmp的返回值不一定是-1, 0, 1,而是<0, =0, >0的某个数。这在windows和linux上的效果不一样。
  • 注意:黑白双方交替走棋。
  • 任意一方都必须走一步。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <set>
#include <cassert>
using namespace std;

const int MAX_N = 10;
const int N = 4;
const int Dir[4][2] = { {1, 0}, {0, 1}, {-1, 0}, {0, -1} };

struct Node
{
	char A[MAX_N][MAX_N];
	int Level;
	char NextColor;

	Node()
	{
		memset(A, 0, sizeof(A));
		Level = 0;
	}

	Node operator = (const Node& a)
	{
		memcpy(A, a.A, sizeof(A));
		Level = a.Level;
		NextColor = a.NextColor;
		return *this;
	}

	bool operator < (const Node& a) const
	{
		if (NextColor != a.NextColor)
			return NextColor == 'B';
		else
			return memcmp(A, a.A, sizeof(A)) < 0;
	}

	bool operator == (const Node& a) const
	{
		return NextColor == a.NextColor && memcmp(A, a.A, sizeof(A)) == 0;
	}

	void OPos1(int &oRow1, int &oCol1)
	{
		for (int row = 1; row <= N; row++)
			for (int col = 1; col <= N; col++)
				if (A[row][col] == 'O')
				{
					oRow1 = row;
					oCol1 = col;
					return;
				}
	}

	void OPos2(int &oRow2, int &oCol2)
	{
		int oRow1, oCol1;
		OPos1(oRow1, oCol1);
		for (int col = oCol1 + 1; col <= N; col++)
			if (A[oRow1][col] == 'O')
			{
				oRow2 = oRow1;
				oCol2 = col;
				return;
			}
		for (int row = oRow1 + 1; row <= N; row++)
			for (int col = 1; col <= N; col++)
				if (A[row][col] == 'O')
				{
					oRow2 = row;
					oCol2 = col;
					return;
				}
		assert(0);
	}

	bool CanMove1(const int dRow, const int dCol)
	{
		int oRow1, oCol1;
		OPos1(oRow1, oCol1);
		int nextRow = oRow1 + dRow, nextCol = oCol1 + dCol;
		return A[nextRow][nextCol] == NextColor && nextRow <= N && nextRow >= 1 && nextCol <= N && nextCol >= 1;
	}

	Node GetMove1(int dRow, int dCol)
	{
		int oRow1, oCol1;
		OPos1(oRow1, oCol1);
		Node ans = *this;
		swap(ans.A[oRow1][oCol1], ans.A[oRow1 + dRow][oCol1 + dCol]);
		return ans;
	}

	bool CanMove2(const int dRow, const int dCol)
	{
		int oRow2, oCol2;
		OPos2(oRow2, oCol2);
		int nextRow = oRow2 + dRow, nextCol = oCol2 + dCol;
		return A[nextRow][nextCol] == NextColor && nextRow <= N && nextRow >= 1 && nextCol <= N && nextCol >= 1;
	}


	Node GetMove2(int dRow, int dCol)
	{
		int oRow2, oCol2;
		OPos2(oRow2, oCol2);
		Node ans = *this;
		swap(ans.A[oRow2][oCol2], ans.A[oRow2 + dRow][oCol2 + dCol]);
		return ans;
	}

	bool Ok()
	{
		for (int row = 1; row <= N; row++)
		{
			char st = A[row][1];
			bool ok = true;
			for (int col = 2; col <= N; col++)
				if (A[row][col] != st)
				{
					ok = false;
					break;
				}
			if (ok)
				return true;
		}
		for (int col = 1; col <= N; col++)
		{
			char st = A[1][col];
			bool ok = true;
			for (int row = 2; row <= N; row++)
				if (A[row][col] != st)
				{
					ok = false;
					break;
				}
			if (ok)
				return true;
		}
		char st = A[1][1];
		bool ok = true;
		for (int i = 2; i <= N; i++)
			if (A[i][i] != st)
			{
				ok = false;
				break;
			}
		if (ok)
			return true;
		st = A[1][N];
		ok = true;
		for (int row = 2, col = N - 1; row <= N; row++, col--)
			if (A[row][col] != st)
			{
				ok = false;
				break;
			}
		return ok;
	}
};
Node Start;

int Bfs()
{
	static queue<Node> q;
	static set<Node> cache;
	Node s1 = Start, s2 = Start;
	s1.NextColor = 'B';
	s2.NextColor = 'W';
	q.push(s1);
	q.push(s2);
	cache.insert(s1);
	cache.insert(s2);
	while (!q.empty())
	{
		Node cur = q.front();
		q.pop();
		if (!(cur == s1 || cur == s2) && cur.Ok())
			return cur.Level;
		for (int i = 0; i < 4; i++)
		{
			if (cur.CanMove1(Dir[i][0], Dir[i][1]))
			{
				Node next = cur.GetMove1(Dir[i][0], Dir[i][1]);
				next.NextColor = (cur.NextColor == 'B' ? 'W' : 'B');
				if (!cache.count(next))
				{
					next.Level = cur.Level + 1;
					cache.insert(next);
					q.push(next);
				}
			}
			if (cur.CanMove2(Dir[i][0], Dir[i][1]))
			{
				Node next = cur.GetMove2(Dir[i][0], Dir[i][1]);
				next.NextColor = (cur.NextColor == 'B' ? 'W' : 'B');
				if (!cache.count(next))
				{
					next.Level = cur.Level + 1;
					cache.insert(next);
					q.push(next);
				}
			}
		}
	}
	return -1;
}

int main()
{
	for (int i = 1; i <= 4; i++)
		scanf("%s", Start.A[i] + 1);
	printf("%d\n", Bfs());
	return 0;
}

  

posted @ 2018-09-17 23:29  headboy2002  阅读(221)  评论(0编辑  收藏  举报