华容道穷举算法实现

1、广度优先的树型结构

由于整个棋局的可行解可以描述成一个树型结构,并且为了得到最少移动步数需要采用广度优先的搜索算法,因此考虑将链表与树型结构整合起来,便于进行广度搜索。如图,当我们试图搜索第三步可行解时,只需要顺着第二步的链表依次搜索便可以实现了。

2、堆栈结构输出最少步数

由于在树型结构设计上,每个子节点都保留了一个对父节点的引用。所以一旦找到最优解,我们就需要从最底层向上追溯所有移动步骤(如下图)。但这个顺序与走棋的顺序正好相反。借助一个堆栈结构实现后进先出便把这个次序逆转过来了。



本次算法实现的算法采用的是穷举,实现机制就是如上图所示,代码比较简单,直接上代码:

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

struct State
{
	State *father;
	int state[5][4];
	State *next;
};

State *current;
const State *head = current;
State *next_node;

void show_state(State *c)
{
	for (int i = 0; i < 5; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			cout << c->state[i][j] << " | ";
		}
		cout << endl;
	}
}
void input_initial_state(int p[][4], State &root)
{
	int i;
	cout << "select num :";
	cin >> i;
	switch (i){
	case 1:
			p[0][0] = 2; p[0][1] = 6; p[0][2] = 6; p[0][3] = 7;
			p[1][0] = 2; p[1][1] = 1; p[1][2] = 1; p[1][3] = 3;
			p[2][0] = 4; p[2][1] = 1; p[2][2] = 1; p[2][3] = 3;
			p[3][0] = 4; p[3][1] = 7; p[3][2] = 5; p[3][3] = 7;
			p[4][0] = 0; p[4][1] = 7; p[4][2] = 5; p[4][3] = 0;
			break;//最优解16步
	case 2:
		p[0][0] = 7; p[0][1] = 6; p[0][2] = 6; p[0][3] = 7;
		p[1][0] = 2; p[1][1] = 1; p[1][2] = 1; p[1][3] = 3;
		p[2][0] = 2; p[2][1] = 1; p[2][2] = 1; p[2][3] = 3;
		p[3][0] = 4; p[3][1] = 7; p[3][2] = 7; p[3][3] = 5;
		p[4][0] = 4; p[4][1] = 0; p[4][2] = 0; p[4][3] = 5;
		break;//最优解13步
	case 3:
		p[0][0] = 2; p[0][1] = 3; p[0][2] = 7; p[0][3] = 7;
		p[1][0] = 2; p[1][1] = 3; p[1][2] = 7; p[1][3] = 7;
		p[2][0] = 4; p[2][1] = 5; p[2][2] = 6; p[2][3] = 6;
		p[3][0] = 4; p[3][1] = 5; p[3][2] = 1; p[3][3] = 1;
		p[4][0] = 0; p[4][1] = 0; p[4][2] = 1; p[4][3] = 1;
		break;//最优解22步
	case 4:
		p[0][0] = 1; p[0][1] = 1; p[0][2] = 6; p[0][3] = 6;
		p[1][0] = 1; p[1][1] = 1; p[1][2] = 7; p[1][3] = 7;
		p[2][0] = 0; p[2][1] = 7; p[2][2] = 7; p[2][3] = 0;
		p[3][0] = 2; p[3][1] = 3; p[3][2] = 4; p[3][3] = 5;
		p[4][0] = 2; p[4][1] = 3; p[4][2] = 4; p[4][3] = 5;
		break;//最优解25步
	case 5:
		p[0][0] = 2; p[0][1] = 7; p[0][2] = 3; p[0][3] = 0;
		p[1][0] = 2; p[1][1] = 7; p[1][2] = 3; p[1][3] = 7;
		p[2][0] = 1; p[2][1] = 1; p[2][2] = 4; p[2][3] = 5;
		p[3][0] = 1; p[3][1] = 1; p[3][2] = 4; p[3][3] = 5;
		p[4][0] = 6; p[4][1] = 6; p[4][2] = 7; p[4][3] = 0;
		break;//最优解31步

	case 80:
		p[0][0] = 2; p[0][1] = 6; p[0][2] = 6; p[0][3] = 3;
		p[1][0] = 2; p[1][1] = 7; p[1][2] = 7; p[1][3] = 3;
		p[2][0] = 4; p[2][1] = 1; p[2][2] = 1; p[2][3] = 5;
		p[3][0] = 4; p[3][1] = 1; p[3][2] = 1; p[3][3] = 5;
		p[4][0] = 7; p[4][1] = 0; p[4][2] = 0; p[4][3] = 7;
		break;
	case 81:
		/****************横刀立马**************************/
		p[0][0] = 2; p[0][1] = 1; p[0][2] = 1; p[0][3] = 3;
		p[1][0] = 2; p[1][1] = 1; p[1][2] = 1; p[1][3] = 3;
		p[2][0] = 4; p[2][1] = 6; p[2][2] = 6; p[2][3] = 5;
		p[3][0] = 4; p[3][1] = 7; p[3][2] = 7; p[3][3] = 5;
		p[4][0] = 7; p[4][1] = 0; p[4][2] = 0; p[4][3] = 7;
		break;
		/**************************************************/

	}
	
	
	root.father = NULL;
	root.next = NULL;
}

bool check_repeat(State *p)
{
	State *traverse;
	traverse = (State *)head;
	int record = 0, sum = 0;//record记录对比,sum对比总次数
	while (traverse->next)
	{
		int remark = record;//跳出双循环
		for (int i = 0; i < 5; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				if (p->state[i][j] != traverse->state[i][j])//状态矩阵出现同位置不同元素,认为是2中不同状态
				{
					record = record + 1;
					break;
				}//检查到是一个新状态,记录一次重复
			}
			if (remark != record)break;
		}

		//循环对比后,发现是旧状态
		traverse = traverse->next;
		sum = sum + 1;
	}
	//遍历结束,对比sum和record,若sum==record 代表每次对比都出现不同状态,说明是一种新状态
	if (sum == record)return false;
	else return true;
}

bool is_success(State *p)
{
	if (p->state[3][1] == 1 && p->state[3][2] == 1 && p->state[4][1] == 1 && p->state[4][2] == 1)
	{
		cout << "find vale is ok!" << endl;		
		return true;
	}
	else return false;
}

int move(int a[][4],int i,int j,int x,int y,State * ¤t,State * &next_node)//待移动目标a[i][j],移动到位置a[x][y]
{
	State *p;
	next_node->next = new State;
	p = next_node->next;
	p->next = NULL;

	for (int b = 0; b < 5;b++)
	{
		for (int c = 0; c < 4;c++)
		{
			p->state[b][c] = a[b][c];
		}
	}//建立新状态结点
	int t;
	t = p->state[i][j];
	p->state[i][j] = p->state[x][y];
	p->state[x][y] = t;

	if (check_repeat(p) == true)
	{ 
		delete p;
		next_node->next = NULL;
		return 1;
	};//检查重复

	p->father = current;
	
	//next_node->next = &new_state;
	next_node = p;

	if (is_success(p))
	{
		//找到了目标状态,输出移动过程
		stack <State *> show_way;

		while (next_node->father == NULL)
		{
			show_way.push(next_node);
			next_node = next_node->father;
		}

		State *show; int x = 0;
		show = show_way.top();
		while (show_way.empty() == false)
		{
			cout << "第" << x << "步:" << endl;
			show_state(show);
			show_way.pop();
			x = x + 1;
		}
		exit(0);
	}

	return 0;
}

int move(int a[][4], int i1, int j1, int x1, int y1, int i2, int j2, int x2, int y2, State * ¤t, State * &next_node)
//待移动目标a1[i1][j1],移动到位置a1[x1][y1],待移动目标a2[i2][j2],移动到位置a2[x2][y2]
{
	State *p;
	next_node->next = new State;
	p = next_node->next;
	p->next = NULL;

	for (int b = 0; b < 5; b++)
	{
		for (int c = 0; c < 4; c++)
		{
			p->state[b][c] = a[b][c];
		}
	}//建立新状态结点

	/* 移动 */
	int t;
	t = p->state[i1][j1];
	p->state[i1][j1] = p->state[x1][y1];
	p->state[x1][y1] = t;

	t = p->state[i2][j2];
	p->state[i2][j2] = p->state[x2][y2];
	p->state[x2][y2] = t;

	if (check_repeat(p) == true)
	{
		delete p;
		next_node->next = NULL;
		return 1;
	};//检查重复

	p->father = current;
	//next_node->next = &new_state;
	next_node = p;

	if (is_success(p))
	{
		//找到了目标状态,输出移动过程
		stack <State *> show_way;

		while (next_node->father != NULL)
		{
			show_way.push(next_node);
			next_node = next_node->father;
		}

		State *show; int x = 1;
		show = show_way.top();
		while (show_way.empty() == false)
		{
			cout << "di" << x << "setps:" << endl;
			show_state(show);
			show_way.pop();
			if(show_way.size() != 0)
				show = show_way.top();
			x = x + 1;
		}
		exit(0);
	}


	return 0;
}


bool is_one(int p[][4], int i, int j, State * &c, State * &n)
{
	if (p[i][j] == 1 && p[i][j] == p[i + 1][j] && p[i][j] == p[i][j + 1] && p[i][j] == p[i + 1][j + 1])//is 1 or not
	{
		if (p[i - 1][j] == 0 && p[i - 1][j + 1] == 0 && i > 0){ move(p, i + 1, j, i - 1, j, i + 1, j + 1, i - 1, j + 1, c, n); }//up,2
		if (p[i + 2][j] == 0 && p[i + 2][j + 1] == 0 && i < 3){ move(p, i, j, i + 2, j, i, j + 1, i + 2, j + 1, c, n);  }//down,2
		if (p[i][j - 1] == 0 && p[i + 1][j - 1] == 0 && j > 0){ move(p, i, j + 1, i, j - 1, i + 1, j + 1, i + 1, j - 1, c, n); }//left,2
		if (p[i][j + 2] == 0 && p[i + 1][j + 2] == 0 && j < 2){ move(p, i, j, i, j + 2, i + 1, j, i + 1, j + 2, c, n);  }//right,2
		return true;//move success
	}
	else return 0;//can not move
}

bool is_two(int p[][4], int i, int j, State * &c, State * &n)
{
	if (p[i][j] == p[i + 1][j] && p[i][j] == 2 && p[i + 1][j]==2)//is 2 or not
	{
		if (p[i - 1][j] == 0 && i > 0){ move(p, i + 1, j, i - 1, j,c,n); }//UP
		if (p[i + 2][j] == 0 && i < 3){ move(p, i, j, i + 2, j,c,n); }//DOWN
		if (p[i][j - 1] == 0 && p[i + 1][j - 1] == 0 && j > 0){ move(p, i, j, i, j - 1, i + 1, j, i + 1, j - 1, c, n);  }//left,2
		if (p[i][j + 1] == 0 && p[i + 1][j + 1] == 0 && j < 3){ move(p, i, j, i, j + 1, i + 1, j, i + 1, j + 1, c, n);  }//right,2
		return true;//move success
	}
	else return false;//move faild
}
bool is_three(int p[][4], int i, int j, State * &c, State * &n)
{
	if (p[i][j] == p[i + 1][j] && p[i][j] == 3 && p[i + 1][j] == 3)//is 3 or not
	{
		if (p[i - 1][j] == 0 && i > 0){ move(p, i + 1, j, i - 1, j, c, n); }//UP
		if (p[i + 2][j] == 0 && i < 3){ move(p, i, j, i + 2, j, c, n); }//DOWN
		if (p[i][j - 1] == 0 && p[i + 1][j - 1] == 0 && j > 0){ move(p, i, j, i, j - 1, i + 1, j, i + 1, j - 1, c, n); }//left,2
		if (p[i][j + 1] == 0 && p[i + 1][j + 1] == 0 && j < 3){ move(p, i, j, i, j + 1, i + 1, j, i + 1, j + 1, c, n); }//right,2
		return true;//move success
	}
	else return false;//move faild
}
bool is_four(int p[][4], int i, int j, State * &c, State * &n)
{
	if (p[i][j] == p[i + 1][j] && p[i][j] == 4 && p[i + 1][j] == 4)//is 4 or not
	{
		if (p[i - 1][j] == 0 && i > 0){ move(p, i + 1, j, i - 1, j,c,n); }//UP
		if (p[i + 2][j] == 0 && i < 3){ move(p, i, j, i + 2, j, c, n); }//DOWN
		if (p[i][j - 1] == 0 && p[i + 1][j - 1] == 0 && j > 0){ move(p, i, j, i, j - 1, i + 1, j, i + 1, j - 1, c, n); }//left,2
		if (p[i][j + 1] == 0 && p[i + 1][j + 1] == 0 && j < 3){ move(p, i, j, i, j + 1, i + 1, j, i + 1, j + 1, c, n); }//right,2
		return true;//move success
	}
	else return false;//move faild
}
bool is_five(int p[][4], int i, int j, State * &c, State * &n)
{
	if (p[i][j] == p[i + 1][j] && p[i][j] == 5 && p[i + 1][j] == 5)//is 5 or not
	{
		if (p[i - 1][j] == 0 && i > 0){ move(p, i + 1, j, i - 1, j,c,n); }//UP
		if (p[i + 2][j] == 0 && i < 3){ move(p, i, j, i + 2, j, c, n); }//DOWN
		if (p[i][j - 1] == 0 && p[i + 1][j - 1] == 0 && j > 0){ move(p, i, j, i, j - 1, i + 1, j, i + 1, j - 1, c, n);  }//left,2
		if (p[i][j + 1] == 0 && p[i + 1][j + 1] == 0 && j < 3){ move(p, i, j, i, j + 1, i + 1, j, i + 1, j + 1, c, n);  }//right,2
		return true;//move success
	}
	else return false;//move faild
}

bool is_six(int p[][4], int i, int j, State * &c, State * &n)
{
	if (p[i][j] == p[i][j + 1] && p[i][j] == 6 && p[i][j + 1] == 6)
	{
		if (p[i - 1][j] == 0 && p[i - 1][j + 1] == 0 && i > 0){ move(p, i, j, i - 1, j, i, j + 1, i - 1, j + 1, c, n);  }//up,2
		if (p[i + 1][j] == 0 && p[i + 1][j + 1] == 0 && i < 4){ move(p, i, j, i + 1, j, i, j + 1, i + 1, j + 1, c, n); }//down,2
		if (p[i][j - 1] == 0 && j > 0){ move(p, i, j + 1, i, j - 1, c, n); }//left
		if (p[i][j + 2] == 0 && j < 2){ move(p, i, j, i, j + 2,c,n); }//right
		return true;//move success
	}
	else return false;//move faild
}

bool is_seven(int p[][4], int i, int j, State * &c, State * &n)
{
	if (p[i][j] == 7)
	{
		if (p[i - 1][j] == 0 && i > 0){ move(p, i, j, i - 1, j, c, n); }//up
		if (p[i + 1][j] == 0 && i < 4){ move(p, i, j, i + 1, j, c, n); }//down
		if (p[i][j - 1] == 0 && j > 0){ move(p, i, j, i, j - 1, c, n); }//left
		if (p[i][j + 1] == 0 && j < 3){ move(p, i, j, i, j + 1, c, n); }//right
		return true;//move success
	}
	else return false;//move faild
}

//int a = 0;

void build_tree(State * &c,State * &n)
{
	
	for (int i = 0; i < 5; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			is_one(c->state, i, j, c, n);
			is_two(c->state, i, j, c, n);
			is_three(c->state, i, j, c, n);
			is_four(c->state, i, j, c, n);
			is_five(c->state, i, j, c, n);
			is_six(c->state, i, j, c, n);
			is_seven(c->state, i, j, c, n);
		}
		
	}//判断当前状态图可移动的情况,给每种情况生成子节点

	c = c->next;//当前结点移动到下一个节点

}



int main()
{ 
	cout << "huarongdao games design!" << endl;
	struct State root;
	input_initial_state(root.state,root);
	current = &root;
	next_node = &root;
	head = &root;
	show_state(current);

	while (true)
	{
		build_tree(current, next_node);
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_21792169/article/details/80898811