码迷,mamicode.com
首页 > 其他好文 > 详细

康托展开求八数码问题

时间:2015-01-09 17:22:51      阅读:311      评论:0      收藏:0      [点我收藏+]

标签:算法   c++   sicily   path   

/*
问题描述:
目标状态为:
1 2 3
4 5 6
7 8 0

输入初始状态,求初始状态到最终状态的路径分别
用u(向上),d(向下),l(向左),r(向右)来表示四个方向的移动;
如果有解,则输出路径,否则输出"unsolvable"
有多个输入
*/

#include<iostream>
#include<queue>
#include<string>
#include<cstring>
using namespace std;
long long fac[10] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };
const int direction[4][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };  //0移动的方向
bool closeList[362880 + 10]; //记录一个节点是否被访问过			     // l , r, u, d
char action[5] = "udlr"; //移动的步骤,对应上面的direction
int target = 0; //保存目标状态的康托展开值
int tmptarget[9] = { 1, 2, 3, 4, 5, 6, 7, 8, 0 }; //目标状态
const int num = 3;

struct Node{
	int state[num * num];
	int zero; //0的位置
	string steps; //从初始节点到当前节点的路径
	int cnt; //当前状态的康托展开值
};

//康托展开
int Cantor(int state[9]){
	int id = 0;
	for (size_t i = 0; i < num * num; i++){
		int count = 0;
		for (size_t j = i + 1; j < num * num; j++){
			if (state[i] > state[j])
				count++;
		}
		id += (count * fac[num * num - i - 1]);
	}
	return id + 1;
}

int main(int argc, char *argv[]){
	target = Cantor(tmptarget);
	char ch;
	//1 2 3 4 5 x 7 8 6
	//2 3 4 1 5 x 7 6 8
	while (cin >> ch){ //记得把cin >> ch放在这里,否则会time limit 
		Node head;
		Node next;
		if (ch == 'x'){
			head.zero = 0;
			head.state[0] = 0;
		}
		else
			head.state[0] = ch - '0';
		for (int i = 1; i < num * num; i++){
			cin >> ch; //输入起始状态
			if (ch == 'x'){ //把x换成0
				head.zero = i;
				head.state[i] = 0;
			}
			else
				head.state[i] = ch - '0';
		}
		head.cnt = Cantor(head.state);
		head.steps = "";

		queue<Node> openList;
		bool flag = false; //记录是否达到目标状态
		string path = ""; //记录从起始节点到目标节点的路径
		memset(closeList, false, sizeof(closeList));
		openList.push(head);

		while (!openList.empty() && !flag){
			head = openList.front();
			if (head.cnt == target){ //判断是否达到目标状态
				flag = true;
				path = head.steps;
				break;
			}
			int oldr = head.zero / num; //0所在的行
			int oldc = head.zero % num; //0所在的列
			for (int i = 0; i < 4; i++){
				int newr = oldr + direction[i][0];
				int newc = oldc + direction[i][1];
				if (newr >= 0 && newr < num && newc >= 0 && newc < num){
					next = head;
					next.zero = newr * 3 + newc; //0的新位置
					next.state[head.zero] = head.state[next.zero];
					next.state[next.zero] = 0;
					next.cnt = Cantor(next.state);
					if (!closeList[next.cnt]){
						next.steps = head.steps + action[i];
						if (next.cnt == target){
							flag = true;
							path = next.steps;
							break;
						}
						closeList[next.cnt] = true;
						openList.push(next);
					}
				}
			}
			openList.pop();
		}
		if (flag){ //找到解,输出路径
			cout << path << "\n";
		}
		else{
			cout << "unsolvable" << "\n"; 
		}
	}
	return 0;
}

康托展开求八数码问题

标签:算法   c++   sicily   path   

原文地址:http://blog.csdn.net/liujan511536/article/details/42556883

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!