hdu 1043 eight (八数码+康托展开+记录路径)

Eight

  HDU - 1043 

The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as: 
 1  2  3  4
 5  6  7  8
 9 10 11 12
13 14 15  x

where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle: 
 1  2  3  4     1  2  3  4     1  2  3  4     1  2  3  4
 5  6  7  8     5  6  7  8     5  6  7  8     5  6  7  8
 9  x 10 12     9 10  x 12     9 10 11 12     9 10 11 12
13 14 11 15    13 14 11 15    13 14  x 15    13 14 15  x
            r->            d->            r->

The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively. 

Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and 
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course). 

In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three 
arrangement. 
InputYou will receive, several descriptions of configuration of the 8 puzzle. One description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle 

1 2 3 
x 4 6 
7 5 8 

is described by this list: 

1 2 3 x 4 6 7 5 8 
OutputYou will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line. Do not print a blank line between cases. 
Sample Input
2  3  4  1  5  x  7  6  8
Sample Output
ullddrurdllurdruldr


AC:

#include 
#include 
#include 
using namespace std;
struct node1{
	char way;//路径 
	int pre;//父节点 
}; 
node1 Node[370000];//节点

struct node2{
	int aa[10];
	int n,cnt;//n为 9在aa中的位置,cnt为aa在9的字典序全排列的中的位置 
}; 

int end1[9];//终态 
int fac[10];

int dx[]={1, -1,  0,  0};
int dy[]={0, 0,   1, -1};
//       下  上  右  左 
char paths[]={'u','d','l','r'};//记录路径时记录相反的方向 

void Get_fac()//计算0-9的阶乘 
{
	fac[0]=1;
	for(int i=1;i<=9;i++)
		fac[i]=fac[i-1]*i;
}

int kangtuo(int aa[])//康托展开  
{  
    int i,j,ans=0,k;  
    for(i=0;i<9;i++)  
    {  
        k=0;  
        for(j=i+1;j<9;j++)  
        if(aa[i]>aa[j])  
        	k++;  
        ans+=k*fac[8-i];  
    } 
	ans++; 
    return ans;  
} 

void bfs()
{
	queueQ;
	node2 p,q;
	
	for(int i=0;i<9;i++)
		p.aa[i]=end1[i];
	p.n=8,p.cnt=1;
	Node[p.cnt].pre=1;//终态的父节点为1,即终态为根节点 

	Q.push(p);
	while(!Q.empty())
	{
		p=Q.front();
		Q.pop();
		for(int i=0;i<4;i++)//9与其所在位置的下上右左分别交换位置 
		{
			q=p;
			int tx,ty;
			tx=p.n/3+dx[i];//9的下一个位置的横坐标 
			ty=p.n%3+dy[i];//9的下一个位置的纵坐标 
			if(tx>=0 && tx<3 && ty>=0 && ty<3)//未出界 
			{
				int tnum;
				q.n=tx*3+ty;//计算9的在数组中下一个位置 
				
				tnum=q.aa[p.n];
				q.aa[p.n]=q.aa[q.n];
				q.aa[q.n]=tnum;
				
				q.cnt=kangtuo(q.aa);//康托展开计算当前态在全排列中的位置 
				
				if(Node[q.cnt].pre==-1)//为-1时表示这个点没有访问过,那么放入队列
				{
					Node[q.cnt].pre=p.cnt;//当前节点的父节点就是上一个节点
					Node[q.cnt].way=paths[i];//记录路径 
					Q.push(q);
				}
			}
		}
	} 
}

int main()
{
	for(int i=0;i<9;i++)
		end1[i]=i+1;
	for(int i=0;i<370000;i++)//初始化,每一种情况都未被访问过 
		Node[i].pre=-1;
	Get_fac();
	bfs();//预处理,以终态为根节点建立一树 
	
	char c[20];
	
	while(gets(c)>0)
	{   
		int start1[10];
		int k=0;
		for(int i=0;i='0' && c[i]<='9')
			{
				start1[k++]=c[i]-'0';
			}
		}
		//for(int i=0;i<9;i++);
		/*加上这一句,你会发现不一样的东西(在我电脑上样例输出结果不一样,不
		知道是不是我的编译器的问题 QAQ ),但两种情况都能AC*/ 
		
		int cnt=kangtuo(start1);//算出初态的康托值 
		//printf("%d\n",cnt);
		if(Node[cnt].pre==-1)//终态不能变成初态
		{
			printf("unsolvable\n");
			continue;
		}
		while(cnt!=1)//从现态往回搜,一直到根,结束
		{
			printf("%c",Node[cnt].way);
			cnt=Node[cnt].pre;
		}
		printf("\n");
	}
	return 0;
}

参考代码:点击打开链接

康托展开:点击打开链接

//上面的问题是数组开的太小了,但是侥幸水过了,学长看了下把数组改大就不会出错了,但是还是不知道为什么加个for循环结果就正确了 

#include 
#include 
#include 
using namespace std;
struct node1{
	char way;//路径 
	int pre;//父节点 
}; 

struct node2{
	int aa[10];
	int n,cnt;//
};//节点 

node1 Node[370000];
int end1[9];
int fac[10];

int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
char paths[]={'u','d','l','r'};

void Get_fac()//计算0-9的阶乘 
{
	fac[0]=1;
	for(int i=1;i<=9;i++)
		fac[i]=fac[i-1]*i;
}

int kangtuo(int aa[])//康托展开  
{  
    int j,ans=0,k;  
    for(int i=0;i<9;i++)  
    {  
        k=0;  
        for(j=i+1;j<9;j++)  
        if(aa[i]>aa[j])  
        	k++;  
        ans+=k*fac[8-i];  
    } 
	ans++; 
    return ans;  
} 

void bfs()
{
	queueQ;
	node2 p,q;
	
	for(int i=0;i<9;i++)
		p.aa[i]=end1[i];
	p.n=8,p.cnt=1;
	Node[p.cnt].pre=1;

	Q.push(p);
	while(!Q.empty())
	{
		p=Q.front();
		Q.pop();
		for(int i=0;i<4;i++)
		{
			q=p;
			int tx,ty;
			tx=p.n/3+dx[i];
			ty=p.n%3+dy[i];
			if(tx>=0 && tx<3 && ty>=0 && ty<3)
			{
				int tnum;
				q.n=tx*3+ty;
				
				tnum=q.aa[p.n];
				q.aa[p.n]=q.aa[q.n];
				q.aa[q.n]=tnum;
				
				q.cnt=kangtuo(q.aa);
				
				if(Node[q.cnt].pre==-1)
				{
					Node[q.cnt].pre=p.cnt;
					Node[q.cnt].way=paths[i];
					//printf("%c ",paths[i]);
					Q.push(q);
				}
			}
		}
	} 
}

int main()
{
	for(int i=0;i<9;i++)
		end1[i]=i+1;
	for(int i=0;i<370000;i++)
		Node[i].pre=-1;
	Get_fac();
	bfs();
	
	char c[30];
	//char c[20]; //开20太勉强了,反正内存不要钱,多开一点,避免出现不可预期的错误。 
	
	
	while(gets(c)>0)
	{   
		int start1[10];
		int k=0,i;
		for( i=0;i<40;i++)
		printf("C %c: %d\n",c[i],&c[i]); 
		printf("i %d\n",&i);
		printf("start1[0] %d\nstart1[9] %d\n",&start1[0],&start1[9]);
		printf("k %d\n",&k);
		
		for(int i=0;i='0' && c[i]<='9')
			{
				start1[k++]=c[i]-'0';
			}
		}
		//样例是输入 2  3  4  1  5  x  7  6  8,输出 ullddrurdllurdruldr
		//样例一共9个字符,且字符之间是两个空格,不是一个哦。 
		for(int i=0;i<9;i++);//加这个废的for循环 结果ullddrurdllurrdlurd 正确
		
		//for(int kkk=0;kkk<9;kkk++);//把i替换成前面代码没有用过的变量kkk, 结果还是 ullddrurdllurrdlurd 正确 
		//不加这个for循环             结果lurullddrurdllurdr 这个结果是错误的 
		int cnt=kangtuo(start1);                          

		if(Node[cnt].pre==-1)
		{
			printf("unsolvable\n");
			continue;
		}
		while(cnt!=1)
		{
			printf("%c",Node[cnt].way);
			cnt=Node[cnt].pre;
		}
		printf("\n");
	}
	return 0;
}





你可能感兴趣的:(搜索,康托展开,疑问,记录路径,HDU)