【wikioi】1004 四子連棋

題目鏈接

算法:BFS

//2014-02-05更新

*******************************2013-10-15*******************************

PS:被卡過2天。日期:2013-10-14 ~ 2013-10-15 17:28:21

此題卡了我一天,原因是寬搜時方向搞錯= =(汗= =),而這個錯誤我竟然檢查了好久= =!!

(大神不要笑,我用來超多的代碼來實現= =是別人提交代碼的5倍以上,,,200多行= =)

2014.01.02 PS: 我承認我是腦殘了,現在已會寫bfs,改天有時間修改下,下面這個程序很好的證明了我不會搜索= =

#include <iostream>
#include <cstring>
#include <queue>

using namespace std;
enum pa{NUL, LEFT, UP, RIGHT, DOWN};	//四個方向
enum color{O, W, B};					//白色用W表示,黑色用B表示,NUL就表示空格
struct st
{
	color m[4][4];
	short d;				//次數
	short x1, y1, x2, y2;	//空格的位置
	bool who;				//0表示到白棋走,1表示黑棋走
	pa p1, p2;				//空格之前所在的位置,即以本格子來看從哪個位置是移動之前的狀態
	st& operator= (const st& s)
	{
		memcpy(m, s.m, sizeof(m));
		d=s.d; who=s.who;
		p1=s.p1; p2=s.p2;
		x1=s.x1; x2=s.x2;
		y1=s.y1; y2=s.y2;
		return *this;
	}
	st(){memset(m, 0, sizeof(m)); d=0; x1=x2=y1=y2=-1; p1=p2=NUL; who=1;}
}state;
queue<st> q;
int i, j;

void readin()
{
	char chartemp;
	for(i = 0; i < 4; i++) for(j = 0; j < 4; j++)
	{
		cin >> chartemp;
		if(chartemp == 'W') state.m[i][j] = W;
		else if(chartemp == 'B') state.m[i][j] = B;
		else
		{
			state.m[i][j] = O;
			if(state.x1 == -1)
				state.x1 = i, state.y1 = j;
			else
				state.x2 = i, state.y2 = j;
		}
	}
}

void chu()
{
	st t = state;
	if(t.x1+1<4 && t.m[t.x1+1][t.y1] != O) //第一個空格 向下移
	{
		t.p1 = UP; t.p2 = NUL;
		t.x1++; t.m[t.x1-1][t.y1] = t.m[t.x1][t.y1];
		t.m[t.x1][t.y1] = O; t.d++;
		t.who = t.m[t.x1-1][t.y1]-1; t.who = !t.who;
		q.push(t);
	}
	t = state;
	if(t.x2+1<4 && t.m[t.x2+1][t.y2] != O) //第二個空格 向下移
	{
		t.p2 = UP; t.p1 = NUL;
		t.x2++; t.m[t.x2-1][t.y2] = t.m[t.x2][t.y2];
		t.m[t.x2][t.y2] = O; t.d++;
		t.who = t.m[t.x2-1][t.y2]-1; t.who = !t.who;
		q.push(t);
	}
	t = state;
	if(t.y1+1<4 && t.m[t.x1][t.y1+1] != O) //第一個空格 向右移
	{
		t.p1 = LEFT; t.p2 = NUL;
		t.y1++; t.m[t.x1][t.y1-1] = t.m[t.x1][t.y1];
		t.m[t.x1][t.y1] = O; t.d++;
		t.who = t.m[t.x1][t.y1-1]-1; t.who = !t.who;
		q.push(t);
	}
	t = state;
	if(t.y2+1<4 && t.m[t.x2][t.y2+1] != O) //第二個空格 向右移
	{
		t.p2 = LEFT; t.p1 = NUL;
		t.y2++; t.m[t.x2][t.y2-1] = t.m[t.x2][t.y2];
		t.m[t.x2][t.y2] = O; t.d++;
		t.who = t.m[t.x2][t.y2-1]-1; t.who = !t.who;
		q.push(t);
	}
	t = state;
	if(t.x1 > 0 && t.m[t.x1-1][t.y1] != O) //第一個空格 向上移
	{
		t.p1 = DOWN; t.p2 = NUL;
		t.x1--; t.m[t.x1+1][t.y1] = t.m[t.x1][t.y1];
		t.m[t.x1][t.y1] = O; t.d++;
		t.who = t.m[t.x1+1][t.y1]-1; t.who = !t.who;
		q.push(t);
	}
	t = state;
	if(t.x2 > 0 && t.m[t.x2-1][t.y2] != O) //第二個空格 向上移
	{
		t.p2 = DOWN; t.p1 = NUL;
		t.x2--; t.m[t.x2+1][t.y2] = t.m[t.x2][t.y2];
		t.m[t.x2][t.y2] = O; t.d++;
		t.who = t.m[t.x2+1][t.y2]-1; t.who = !t.who;
		q.push(t);
	}
	t = state;
	if(t.y1 > 0 && t.m[t.x1][t.y1-1] != O) //第一個空格 向左移
	{
		t.p1 = RIGHT; t.p2 = NUL;
		t.y1--; t.m[t.x1][t.y1+1] = t.m[t.x1][t.y1];
		t.m[t.x1][t.y1] = O; t.d++;
		t.who = t.m[t.x1][t.y1+1]-1; t.who = !t.who;
		q.push(t);
	}
	t = state;
	if(t.y2 > 0 && t.m[t.x2][t.y2-1] != O) //第二個空格 向左移
	{
		t.p2 = RIGHT; t.p1 = NUL;
		t.y2--; t.m[t.x2][t.y2+1] = t.m[t.x2][t.y2];
		t.m[t.x2][t.y2] = O; t.d++;
		t.who = t.m[t.x2][t.y2+1]-1; t.who = !t.who;
		q.push(t);
	}
}

bool check(const st& s)
{
	int x, y; pa p; bool bp = 1;
	if(s.p1 != NUL) p = s.p1; else {p = s.p2; bp = 0;}
	switch(p)
	{
		case UP:
			x = (bp?s.x1-1:s.x2-1); y = (bp?s.y1:s.y2);
			break;
		case DOWN:
			x = (bp?s.x1+1:s.x2+1); y = (bp?s.y1:s.y2);
			break;
		case RIGHT:
			x = (bp?s.x1:s.x2); y = (bp?s.y1+1:s.y2+1);
			break;
		case LEFT:
			x = (bp?s.x1:s.x2); y = (bp?s.y1-1:s.y2-1);
			break;
		default:
			return 0;
	}
	if((s.m[x][0]==s.m[x][1]&&s.m[x][1]==s.m[x][2]&&s.m[x][2]==s.m[x][3]) ||
	   (s.m[0][y]==s.m[1][y]&&s.m[1][y]==s.m[2][y]&&s.m[2][y]==s.m[3][y]) ||
	   (s.m[0][0]==s.m[1][1]&&s.m[1][1]==s.m[2][2]&&s.m[2][2]==s.m[3][3]) ||
	   (s.m[0][3]==s.m[1][2]&&s.m[1][2]==s.m[2][1]&&s.m[2][1]==s.m[3][0])  )
		return 1;
	return 0;
}

int main()
{
	readin();
	chu();
	st s, t;
	int n = 0; //迭代
	while(++n != 10000000)
	{
		s = q.front(); q.pop();
		if(check(s)) break;
		t = s;
		// 要判斷是否這個點是從原來方向移動得到的,如果要向上移,則p域就不能是下面,否則會大大損耗空間和時間
		if(t.x1+1<4 && t.p1 != DOWN && t.m[t.x1+1][t.y1] != O && t.m[t.x1+1][t.y1]-1 == t.who) //第一個空格 向下移
		{
			t.p1 = UP; t.p2 = NUL;
			t.x1++; t.m[t.x1-1][t.y1] = t.m[t.x1][t.y1];
			t.m[t.x1][t.y1] = O; t.d++; t.who = !t.who;
			q.push(t);
		}
		t = s;
		if(t.x2+1<4 && t.p2 != DOWN && t.m[t.x2+1][t.y2] != O && t.m[t.x2+1][t.y2]-1 == t.who) //第二個空格 向下移
		{
			t.p2 = UP; t.p1 = NUL;
			t.x2++; t.m[t.x2-1][t.y2] = t.m[t.x2][t.y2];
			t.m[t.x2][t.y2] = O; t.d++; t.who = !t.who;
			q.push(t);
		}
		t = s;
		if(t.y1+1<4 && t.p1 != RIGHT && t.m[t.x1][t.y1+1] != O && t.m[t.x1][t.y1+1]-1 == t.who) //第一個空格 向右移
		{
			t.p1 = LEFT; t.p2 = NUL;
			t.y1++; t.m[t.x1][t.y1-1] = t.m[t.x1][t.y1];
			t.m[t.x1][t.y1] = O; t.d++; t.who = !t.who;
			q.push(t);
		}
		t = s;
		if(t.y2+1<4 && t.p2 != RIGHT && t.m[t.x2][t.y2+1] != O && t.m[t.x2][t.y2+1]-1 == t.who) //第二個空格 向右移
		{
			t.p2 = LEFT; t.p1 = NUL;
			t.y2++; t.m[t.x2][t.y2-1] = t.m[t.x2][t.y2];
			t.m[t.x2][t.y2] = O; t.d++; t.who = !t.who;
			q.push(t);
		}
		t = s;
		if(t.x1 > 0 && t.p1 != UP && t.m[t.x1-1][t.y1] != O && t.m[t.x1-1][t.y1]-1 == t.who) //第一個空格 向上移
		{
			t.p1 = DOWN; t.p2 = NUL;
			t.x1--; t.m[t.x1+1][t.y1] = t.m[t.x1][t.y1];
			t.m[t.x1][t.y1] = O; t.d++; t.who = !t.who;
			q.push(t);
		}
		t = s;
		if(t.x2 > 0 && t.p2 != UP && t.m[t.x2-1][t.y2] != O && t.m[t.x2-1][t.y2]-1 == t.who) //第二個空格 向上移
		{
			t.p2 = DOWN; t.p1 = NUL;
			t.x2--; t.m[t.x2+1][t.y2] = t.m[t.x2][t.y2];
			t.m[t.x2][t.y2] = O; t.d++; t.who = !t.who;
			q.push(t);
		}
		t = s;
		if(t.y1 > 0 && t.p1 != LEFT && t.m[t.x1][t.y1-1] != O && t.m[t.x1][t.y1-1]-1 == t.who) //第一個空格 向左移
		{
			t.p1 = RIGHT; t.p2 = NUL;
			t.y1--; t.m[t.x1][t.y1+1] = t.m[t.x1][t.y1];
			t.m[t.x1][t.y1] = O; t.d++; t.who = !t.who;
			q.push(t);
		}
		t = s;
		if(t.y2 > 0 && t.p2 != LEFT && t.m[t.x2][t.y2-1] != O && t.m[t.x2][t.y2-1]-1 == t.who) //第二個空格 向左移
		{
			t.p2 = RIGHT; t.p1 = NUL;
			t.y2--; t.m[t.x2][t.y2+1] = t.m[t.x2][t.y2];
			t.m[t.x2][t.y2] = O; t.d++; t.who = !t.who;
			q.push(t);
		}
	}

	cout << s.d << endl;
	return 0;
}

*******************************2014-02-05*******************************

算法:BFS+Hash判重

裸BFS後,看了題解,有 Hash判重 知識,可算長姿勢了。

Hash判重:將圖看成一串數字,我們可以發現,這可以當作n進制的數看待,那麼hash就有着落了。。我們將這個n進制數轉換爲十禁止,再開個數組,就可以hash了

這題的圖元素只有3個,那麼我們就可以將它看成3進制數來做hash。

注意:做hash的時候的mod要用質數(自己想爲什麼),因爲這個圖的長度爲16,有7個2,那麼經過粗略計算,這個hash的mod在40700000的後面,自己寫了個小prime判定,找出了一個質數 40700017,就用它了。

代碼:

#include <iostream>
#include <cstring>
using namespace std;

struct Map {
	int m[4][4], x1, x2, y1, y2;
	int ans, who;
	Map& operator= (Map& a) { memcpy(m, a.m, sizeof(a.m)); x1=a.x1; x2=a.x2; y1=a.y1; y2=a.y2; ans=a.ans; who=a.who; return *this; }
}q[600009]; //我們模擬隊列,開那麼多應該夠了吧。。不夠就用循環隊列
Map t; //作爲全局temp

const int mod = 40700017;
bool Hash[mod];

bool check(int f) {
	//判斷行和列
	for(int i = 0; i < 4; ++i)
		if( (q[f].m[i][0]==q[f].m[i][1] && q[f].m[i][1]==q[f].m[i][2] && q[f].m[i][2]==q[f].m[i][3]) ||
			(q[f].m[0][i]==q[f].m[1][i] && q[f].m[1][i]==q[f].m[2][i] && q[f].m[2][i]==q[f].m[3][i]) )
			return true;
	//判斷斜邊
	if( (q[f].m[0][0]==q[f].m[1][1] && q[f].m[1][1]==q[f].m[2][2] && q[f].m[2][2]==q[f].m[3][3]) ||
		(q[f].m[0][3]==q[f].m[1][2] && q[f].m[1][2]==q[f].m[2][1] && q[f].m[2][1]==q[f].m[3][0]) )
		return true;
	return false;
}

void swap(int x, int y, int xx, int yy, int w) {
	t.m[x][y] = t.m[xx][yy];
	t.m[xx][yy] = 0;
	if(w == 1) t.x1 = xx, t.y1 = yy;
	else	   t.x2 = xx, t.y2 = yy;
	t.who = t.m[x][y];
}

bool hash(Map& s) {
	//k是3^x次方的結果
	int i, j, k = 1, h = 0;
	for(i = 0; i < 4; ++i)
		for(j = 0; j < 4; ++j) {
			h += s.m[i][j] * k;
			k *= 3;
		}
	h %= mod;
	if(Hash[h]) return false;
	Hash[h] = 1;
	return true;
}

void bfs() {
	int f = 0, l = 1;
	int x1, y1, x2, y2;
	while(f != l) {
		if(check(f)) { cout << q[f].ans; break; }
		q[f].ans++;
		x1 = q[f].x1; y1 = q[f].y1; x2 = q[f].x2; y2 = q[f].y2;
		//8種情況。。我承認可以簡略代碼的,但是算了。這樣看起來壯觀 >_<
		if(x1 > 0 && q[f].m[x1-1][y1] != q[f].who) { t = q[f]; swap(x1, y1, x1-1, y1, 1); if(hash(t)) q[l++] = t; }
		if(x1 < 3 && q[f].m[x1+1][y1] != q[f].who) { t = q[f]; swap(x1, y1, x1+1, y1, 1); if(hash(t)) q[l++] = t; }
		if(y1 > 0 && q[f].m[x1][y1-1] != q[f].who) { t = q[f]; swap(x1, y1, x1, y1-1, 1); if(hash(t)) q[l++] = t; }
		if(y1 < 3 && q[f].m[x1][y1+1] != q[f].who) { t = q[f]; swap(x1, y1, x1, y1+1, 1); if(hash(t)) q[l++] = t; }
		if(x2 > 0 && q[f].m[x2-1][y2] != q[f].who) { t = q[f]; swap(x2, y2, x2-1, y2, 2); if(hash(t)) q[l++] = t; }
		if(x2 < 3 && q[f].m[x2+1][y2] != q[f].who) { t = q[f]; swap(x2, y2, x2+1, y2, 2); if(hash(t)) q[l++] = t; }
		if(y2 > 0 && q[f].m[x2][y2-1] != q[f].who) { t = q[f]; swap(x2, y2, x2, y2-1, 2); if(hash(t)) q[l++] = t; }
		if(y2 < 3 && q[f].m[x2][y2+1] != q[f].who) { t = q[f]; swap(x2, y2, x2, y2+1, 2); if(hash(t)) q[l++] = t; }
		f++;
	}
}

int main() {
	char t; bool ok = 1;
	for(int i = 0; i < 4; ++i) for(int j = 0; j < 4; ++j) {
		cin >> t;
		switch(t) {
		case 'B': q[0].m[i][j] = 2; break;
		case 'W': q[0].m[i][j] = 1; break;
		case 'O': q[0].m[i][j] = 0;
				  if(ok) q[0].x1 = i, q[0].y1 = j, ok = 0;
				  else	 q[0].x2 = i, q[0].y2 = j;
				  break;
		}
	}
	bfs();
	return 0;
}

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章