uva 10181 - 15-Puzzle Problem 十五数码 IDA*

照上一个题八数码修改来的,只是十五数码和八数码判断是否有解的方法不同,八数码0的移动不影响其余7个数字逆序数的奇偶性,而十五数码0的左右移动不影响其余15个数逆序数的奇偶性(顺序不变),但上下移动改变奇偶(移动三次),加上0的话16个数逆序数左右改变(移动一次),上下也改变(移动7次),需要注意每次移动0的距离奇偶性也改变(0到目标位置的曼哈顿距离不是加1就是减一),所以16个数逆序数与0的距离之和s的奇偶性不因0的滑动而改变,初始时s是奇数,所以只有s是奇数的状态才是可到达的

#include<stdio.h>
#include<string.h>
#include<math.h>
#define size 4
int move[4][2]={{-1,0},{0,-1},{0,1},{1,0}};//上 左 右 下
char op[4]={'U','L','R','D'};
int map[size][size],map2[size*size],limit,path[100];
int flag,length;
//int goal_st[3][3]={{1,2,3},{4,5,6},{7,8,0}};
int goal[16][2]= {{3,3},{0,0},{0,1}, {0,2},{0,3}, {1,0}, 
			{1,1}, {1,2}, {1,3},{2,0}, {2,1}, {2,2},{2,3},{3,0},{3,1},{3,2}};;//目标位置
int nixu(int a[size*size])
{
	int i,j,ni,w,x,y;
	ni=0;
	for(i=0;i<size*size;i++)
	{
        if(a[i]==0)
			w=i;
		for(j=i+1;j<size*size;j++)
		{
			if(a[i]>a[j])
				ni++;
		}
	}
	x=w/size;
	y=w%size;
	ni+=abs(x-3)+abs(y-3);
	if(ni%2==1)
		return 1;
	else
		return 0;
}
int hv(int a[][size])//估价函数,曼哈顿距离,小等于实际总步数
{
	int i,j,cost=0;
	for(i=0;i<size;i++)
	{
		for(j=0;j<size;j++)
		{
			int w=map[i][j];
			cost+=abs(i-goal[w][0])+abs(j-goal[w][1]);
		}
	}
	return cost;
}
void swap(int*a,int*b)
{
	int tmp;
	tmp=*a;
	*a=*b;
	*b=tmp;
}
void dfs(int sx,int sy,int len,int pre_move)//sx,sy是空格的位置
{
	int i,j,nx,ny;
	if(flag)
		return;
	int dv=hv(map);
	if(len==limit)
	{
		if(dv==0)
		{
			flag=1;
			length=len;
			return;
		}
		else
			return;
	}
	else if(len<limit)
	{
		if(dv==0)
		{
			flag=1;
			length=len;
			return;
		}
	}
	for(i=0;i<4;i++)
	{
		if(i+pre_move==3&&len>0)//不和上一次移动方向相反,对第二步以后而言
			continue;    
		nx=sx+move[i][0];
		ny=sy+move[i][1];
		if(0<=nx&&nx<size && 0<=ny&&ny<size)
		{
			swap(&map[sx][sy],&map[nx][ny]);
			int p=hv(map);
			if(p+len<=limit&&!flag)
			{
				path[len]=i;
				dfs(nx,ny,len+1,i);
				if(flag)
					return;
			}
			swap(&map[sx][sy],&map[nx][ny]);
		}
	}
}
int main()
{
	int i,j,k,l,m,n,sx,sy;
	char c,g;
	i=0;
	scanf("%d",&n);
	while(n--)
	{
		flag=0;length=0;
		memset(path,-1,sizeof(path));

		for(i=0;i<16;i++)
		{
			scanf("%d",&map2[i]);
			if(map2[i]==0)
			{ 
				map[i/size][i%size]=0;
				sx=i/size;sy=i%size;
			}
			else
			{
				map[i/size][i%size]=map2[i];
			}
		
		}
		if(nixu(map2)==1)//该状态可达
		{
			limit=hv(map);
			while(!flag&&length<=50)//题中要求50步之内到达
			{
				dfs(sx,sy,0,0);
				if(!flag)
				limit++; //得到的是最小步数
			}
			if(flag)
			{
				for(i=0;i<length;i++)
				printf("%c",op[path[i]]);
				printf("\n");
			}
		}
		else if(!nixu(map2)||!flag)
			printf("This puzzle is not solvable.\n");
	}
	return 0;
}
/*
2
2 3 4 0
1 5 7 8
9 6 10 12
13 14 11 15
13 1 2 4
5 0 3 7
9 6 10 12
15 8 11 14

LLLDRDRDR
This puzzle is not solvable.
*/
十五数码的用bfd和A*都会卡死


你可能感兴趣的:(uva 10181 - 15-Puzzle Problem 十五数码 IDA*)