AI八数码问题 Stack Overflow

2019-03-25 13:52|来源: 网路

AI课本八数码问题,我是用广度优先搜索,用Ismatch来记录状态是否已经遍历,个人感觉算法基本没错吧!可是编译程序的时候只要步数长一点(5步可以输出)就没有输出,用Debug调试显示是:Stack Overflow。我看了很久的代码,也没有搞懂需要在哪里做优化。希望大家看下给点意见。谢谢
#include <stdio.h>
#include <string.h>
#define M 362881

bool IsAnswer = false;
bool Ismatch[M];//标记是否已经遍历过
int tos,len;//队列指针tos,长度len
int tt[9]={1,1,2,6,24,120,720,5040,40320};
char dest[10];//目标状态
char tmap[10];
enum dir{up,down,left,right,none};

struct {
	int dir;
	int t;
}path[M];//记录路径

struct eightnum{
	char map[10];
	int x,y;
	int father;
	dir myDir;//父节点移动的方向
}num[M];
eightnum temp;

void back_push(eightnum _num)//push
{
	strcpy(num[len].map, _num.map);
	num[len].x = _num.x;
	num[len].y = _num.y;
	num[len].father = _num.father;
	num[len].myDir = _num.myDir;
	++len;
}

eightnum front_pop()//pop
{
	tos++;
	if(tos<len)
		return num[tos];
	else
		printf("Wrong about the queue!\n");
}

int getHash(char _map[])//获取hash
{
	int hash;
	int k,l;
	hash = 0;
	int count = 0; 
	for(k=0;k<9;++k){
		count = 0;
		for(l = 0 ; l < k ;++ l){
			if(_map[k]<_map[l])
				count++;
		}
		hash += count*tt[k];
	}
	return hash;
}

int ReverseNum(char _map[])//逆序数
{
	int k,l;
	int count = 0;
	for(k=0;k<9;++k){
		for(l = 0 ; l < k ;++ l){
			if(_map[k] == '0')
				continue;
			else if(_map[k]<_map[l])
				count++;
		}
	}
	return count;
}

void DFS(eightnum _tmp)//dfs
{
	getHash(_tmp.map);
	if(strcmp(_tmp.map,dest)==0){//find the answer
		IsAnswer = true;
		printf("Find the path!\n");
		return;
	}
	else if(len>=M){//flow
		printf("Above Flow!");
		return ;
	}
	else{
		//down
		if( _tmp.x != 2){
			strcpy(tmap,_tmp.map);
			char m_tmp;
			m_tmp = tmap[_tmp.x*3+_tmp.y];
			tmap[_tmp.x*3+_tmp.y] = tmap[(_tmp.x+1)*3+_tmp.y];
			tmap[(_tmp.x+1)*3+_tmp.y] = m_tmp;
			int m_hash = getHash(tmap);
			if(Ismatch[m_hash]==false){
				Ismatch[m_hash] = true;
				strcpy(temp.map,tmap);
				temp.x = _tmp.x + 1;
				temp.y = _tmp.y;
				temp.father = tos;
				temp.myDir = down;
				back_push(temp);
			}
		}
		//right
		if( _tmp.y != 2 ){
			strcpy(tmap,_tmp.map);
			char m_tmp;
			m_tmp = tmap[(_tmp.x)*3+_tmp.y];
			tmap[(_tmp.x)*3+_tmp.y]= tmap[(_tmp.x)*3+_tmp.y+1];
			tmap[(_tmp.x)*3+_tmp.y+1] = m_tmp;
			int m_hash = getHash(tmap);
			if(Ismatch[m_hash]==false){
				Ismatch[m_hash] = true;
				strcpy(temp.map,tmap);
				temp.x = _tmp.x;
				temp.y = _tmp.y+1;
				temp.father = tos;
				temp.myDir = right;
				back_push(temp);
			}
		}
		//up
		if(_tmp.x != 0){
			strcpy(tmap,_tmp.map);
			char m_tmp;
			m_tmp = tmap[_tmp.x*3+_tmp.y];
			tmap[_tmp.x*3+_tmp.y] = tmap[(_tmp.x-1)*3+_tmp.y];
			tmap[(_tmp.x-1)*3+_tmp.y] = m_tmp;
			int m_hash = getHash(tmap);
			if(Ismatch[m_hash]==false){
				Ismatch[m_hash] = true;
				strcpy(temp.map,tmap);
				temp.x = _tmp.x - 1;
				temp.y = _tmp.y;
				temp.father = tos;
				temp.myDir = up;
				back_push(temp);
			}
		}
		//left
		if( _tmp.y != 0 ){
			strcpy(tmap,_tmp.map);
			char m_tmp;
			m_tmp = tmap[_tmp.x*3+_tmp.y];
			tmap[_tmp.x*3+_tmp.y]= tmap[(_tmp.x)*3+_tmp.y-1];
			tmap[(_tmp.x)*3+_tmp.y-1] = m_tmp;
			int m_hash = getHash(tmap);
			if(Ismatch[m_hash]==false){
				Ismatch[m_hash] = true;
				strcpy(temp.map,tmap);
				temp.x = _tmp.x;
				temp.y = _tmp.y-1;
				temp.father = tos;
				temp.myDir = left;
				back_push(temp);
			}
		}
		

	}
	eightnum m_tmp = front_pop();
	DFS(m_tmp);
}


void myDisplay(char _map[]){//display
	int ii;
	for(ii=0;ii<9;++ii){
		if(0==ii%3)
			printf("\n");
		if(_map[ii] == '0')
			printf("    ");
		else
			printf("%c   ",_map[ii]);
	}
	printf("\n-----------------------------\n");
}


int main()
{
	char input[10] ;//输入
	strcpy(input,"283164705");
	strcpy(dest,"123804765");
	int i;
	tos =  -1;
	len  = 0;	
	strcpy(temp.map,input);
	printf("原始状态:\n");
	myDisplay(input);
	for(i=0;i<M;++i)
		Ismatch[i] = false;
	if( ReverseNum(input)%2 != ReverseNum(dest)%2){
		printf("Not exist the answer!\n");
		return 1;
	}
	for(i=0;i<10;++i){
		if(temp.map[i] == '0'){
			Ismatch[getHash(temp.map)] = true;
			temp.x = i/3;
			temp.y = i%3;
			temp.father=-1;
			temp.myDir = none;
			back_push(temp);
			break;
		}
	}
	eightnum _tmp = front_pop();
	DFS(_tmp);
	int kk = 0;
	if (IsAnswer){
		int ff = tos ;
		while( num[ff].father != -1){
			path[kk].dir = num[ff].myDir;
			path[kk].t =  ff;
			kk++;
			//printf("%d",num[ff].myDir);	
			ff = num[ff].father;
		}
	}	
	
	for(i=kk-1;i>=0;--i)
	{
		if(path[i].dir==0){
			printf("down-->");
			myDisplay(num[path[i].t].map);
		}
		else if(path[i].dir==1){
			printf("up-->");
			myDisplay(num[path[i].t].map);
		}
		else if(path[i].dir==2){
			printf("right-->");
			myDisplay(num[path[i].t].map);
		}
		else if(path[i].dir==3){
			printf("left-->");
			myDisplay(num[path[i].t].map);
		}
	}
	return 0;
}


ps:用“在link option中增加/stack”这种方法可以实现步长到27,我是想知道是否有更好的方法可以优化代码

相关问答

更多
  • 维基百科 : 在软件中,当调用堆栈使用太多内存时,会发生堆栈溢出。 在许多编程语言中,调用堆栈包含有限的内存量,通常在程序开始时确定。 该堆栈是一个数据结构,用于记录程序的子例程在完成执行时应将控制权返回给的点的记录。 当子程序被调用时,返回地址被压入栈中,当子程序结束执行时,返回地址被从栈中取出 。 如果有许多子程序并且堆栈中没有空间,则会发生堆栈溢出。 同样在堆栈中的目的是存储局部变量,所以如果局部变量太大,更可能堆栈没有空间来存储它,如果这种情况发生堆栈溢出。 当DrawLine子程序从另一个名为Dr ...
  • 所以看起来只有一些设备有这个问题; 我不知道为什么会这样,但这是我的工作。 try { // Transition drawable with a transparent drawable and the final bitmap TransitionDrawable td = new TransitionDrawable(new Drawable[] { aImageView.getDrawable(), ...
  • 如果您只是想知道是否有办法设置堆栈大小,那么谷歌就是您的朋友。 处理是用Java编写的,因此google搜索“java set stack size”这样的东西将是一个很好的起点。 实际上,StackOverflow多次询问了这个问题: 如何增加Java堆栈大小? Java堆栈溢出错误 - 如何在Eclipse中增加堆栈大小? Java Applet:增加堆栈大小 java设置最大堆栈大小 Java默认堆栈大小 但是,由于您正在使用Processing,因此您必须将其导出为可运行的jar,或者从eclips ...
  • 看看http://www.osqa.net/ 。 我相信这是基于python / Django的。 Take a look at http://www.osqa.net/. It's python/Django based I believe.
  • 他们使用名为WMD Markdown Editor的HTML编辑器。 They use an HTML editor called WMD Markdown Editor.
  • 不,将其声明为static不会导致无限循环。 这是为什么。 静态变量在类加载时间内初始化。 因此,当您的类第一次加载时,编译器将为静态变量创建一个实例,就是这样。 这不会导致您的类第二次加载。 由于您的课程未再次加载,因此不会重复此过程。 如果你将它声明为非静态属性,那么这是一个完全不同的故事。 考虑一下 - public class stack { stack obj = new stack(); ........ } 该声明相当于 - public class stack { ...
  • 因为即使在具有大量可用虚拟内存的现代系统上,调用堆栈的最大大小通常也被故意限制为1MB。 这通常不是一个基本限制; 可以修改它(在Linux中使用例如setrlimit() ,或者在Java中使用-Xss标志 )。 但需要这样做通常表示程序异常; 如果你有大型数据集,它们通常应该存储在堆上。 Because even on modern systems with lots of virtual memory available, the maximum size of the call stack is u ...
  • 在标准Lua中,您可以使用lua_pop函数从Lua堆栈中删除项目。 有关此用法的提示,请参阅此答案 。 如果您反复调用代码,最简单的方法是在处理之前存储堆栈的高度,然后将其恢复: int top = lua_gettop(L); ... /* some processing involving the stack*/ lua_settop(L, top); 现在,我不知道如何在Kahlua实现这一目标。 但是在源代码中我看到LuaCallFrame.getTop()和LuaCallFrame.setTo ...
  • EBP是当前堆栈帧的基指针。 一旦用新值覆盖该基指针,对堆栈上项目的后续引用将不会引用堆栈的实际地址,而是引用刚刚提供的覆盖地址。 程序的进一步行为取决于堆栈随后是否以及如何在代码中使用。 EBP is the base pointer for the current stack frame. Once you overwrite that base pointer with a new value, subsequent references to items on the stack will refe ...
  • 我不知道该怎么做,但是。 .. 如果你看看这个答案: jQueryUI:我如何自定义格式化Autocomplete插件结果? 你可以看到有一种方法可以摆弄jQuery的渲染逻辑来改变菜单项的显示方式。 还有一个名为renderMenu的内部jQuery函数,它实际上提供了选择。 我没试过这个,但我想通过打开那个黑盒子,并且替换或重新调整renderMenu及其相关功能,你就可以做你想要的 - 在实际的文本框中只渲染一个项目。 无论如何,这就是我要开始的地方。 编辑 我在jQuery UI中再次查看了自动填充 ...