题目链接
太太太棒了,又又又学到了许多
Problem Description
Eight-puzzle, which is also called “Nine grids”, comes from an old game.
In this game, you are given a 3 by 3 board and 8 tiles. The tiles are numbered from 1 to 8 and each covers a grid. As you see, there is a blank grid which can be represented as an ‘X’. Tiles in grids having a common edge with the blank grid can be moved into that blank grid. This operation leads to an exchange of ‘X’ with one tile.
We use the symbol ‘r’ to represent exchanging ‘X’ with the tile on its right side, and ‘l’ for the left side, ‘u’ for the one above it, ‘d’ for the one below it.
A state of the board can be represented by a string S using the rule showed below.
The problem is to operate an operation list of ‘r’, ‘u’, ‘l’, ‘d’ to turn the state of the board from state A to state B. You are required to find the result which meets the following constrains:
- It is of minimum length among all possible solutions.
- It is the lexicographically smallest one of all solutions of minimum length.
Input
The first line is T (T <= 200), which means the number of test cases of this problem.
The input of each test case consists of two lines with state A occupying the first line and state B on the second line.
It is guaranteed that there is an available solution from state A to B.
Output
For each test case two lines are expected.
The first line is in the format of “Case x: d”, in which x is the case number counted from one, d is the minimum length of operation list you need to turn A to B.
S is the operation list meeting the constraints and it should be showed on the second line.
Sample Input
2
12X453786
12345678X
564178X23
7568X4123
Sample Output
Case 1: 2
dd
Case 2: 8
urrulldr
大致题意
其实和第一题一样,只不过这次的结果是不固定的
具体思路
题目一中不是以结尾是12345678X化作0作为广搜起点吗,一开始把结尾换做数字200组数据自己跑,T了。。。(正常,淡定),后面看博客时候发现了二次映射,除X之外的所有制按照顺序映射
123X65487-->123045678
1-->1 2-->2 3-->3
x-->0 6-->4 5-->5
4-->6 8-->7 7-->8
这样一来其实不难发现,结果只有以下九种
"012345678","102345678","120345678",
"123045678","123405678","123450678",
"123456078","123456708","123456780"
那么一来,只要把这九种结果bfs预处理以下就可以了,手法和第一题一样
在这里有个需要注意的,输出步数最少,且按照字典序最小输出,这便要求我们bfs的时候按照字典序先后for循环了,但这么一来,第一题原本是广搜上一步,在这里需要广搜下一步
120 123 我们不难看出当以结果bfs下一步 123 123 120
453 --> 456 456 --> 450 --> 453
786 780 780 786 786
在这里我们输出的是uu与原有的标准答案相反,因为是以结果下一步bfs,每一步记录上一步
接下来我们看个神奇的东西(开始bfs走
123 120 我们不难看出当以开始bfs下一步 120 123 123
456 --> 453 453 450 --> 456
780 786 786 786 780
此时输出就是dd,我们可以根据结果bfs到起点,步骤相反转换为,起点到重点方向相同
在这里也许有人会问,本来不就是起点到终点吗,但是起点是随机的,只有结果是固定的九种,所以只能以终点bfs,题目又要求字典序,所以只能以正向步骤,一旦结果转换,未必满足字典序(WA了好几发发现的)在这里我们就需要去以开始作为终点,这里因为起点是随机的,我们需要将其映射为九种的情况,最后从终点回溯回去,因为回溯是从后往前,于是用了个栈来使得结果正过来
#include<bits/stdc++.h>
using namespace std;
int factorial[10]= {1,1,2,6,24,120,720,5040,40320};
char endresult[15][10] = {"012345678","102345678","120345678",
"123045678","123405678","123450678",
"123456078","123456708","123456780"
};
int change[4][2]={{1,0},{0,-1},{0,1},{-1,0}};
char dic[10]={'d','l','r','u'};
int flags[400000];
char mapping[10];
struct Node
{
int s,xy;
Node() {}
Node(int S,int XY)
{
s=S,xy=XY;
}
};
struct Path
{
int from,opt;
} p[10][400000];
int getnum(int v)
{
int sum=0;
for (int i=0; i<=8; i++)
{
for (int j=i+1; j<=8; j++)
{
if (endresult[v][i]-'0'>endresult[v][j]-'0')
{
sum=sum+factorial[8-i];
}
}
}
return sum;
}
void Swap(int x,int y)
{
char d;
d=endresult[9][x];
endresult[9][x]=endresult[9][y];
endresult[9][y]=d;
}
void getstr(int v)
{
int tmp[10],flag[10];
memset(flag,0,sizeof(flag));
for (int i=0; i<=8; i++)
{
tmp[i]=v/factorial[8-i];
v=v%factorial[8-i];
}
for (int i=0; i<=8; i++)
{
int num=0;
for (int j=0; j<=8; j++)
{
if (flag[j]==0)
{
num++;
}
if (num==tmp[i]+1)
{
endresult[9][i]=j+1+'0';
flag[j]=1;
break;
}
}
}
}
void bfs(int S,int XY,int V)
{
memset(flags,0,sizeof(flags));
queue<Node>dui;
dui.push(Node(S,XY));
flags[S]=1;
p[V][S].from=-1;
p[V][S].opt=-1;
while (!dui.empty())
{
Node now=dui.front();
dui.pop();
int x=now.xy/3;
int y=now.xy%3;
getstr(now.s);
for (int i=0; i<4; i++)
{
int xx=x+change[i][0];
int yy=y+change[i][1];
if (!(xx>=0&&yy>=0&&xx<3&&yy<3))
{
continue;
}
int newxy=3*xx+yy;
Swap(newxy,now.xy);
int newnum=getnum(9);
if (flags[newnum]==1)
{
Swap(newxy,now.xy);
continue;
}
p[V][newnum].from=now.s;
p[V][newnum].opt=i;
flags[newnum]=1;
dui.push(Node(newnum,newxy));
Swap(newxy,now.xy);
}
}
}
void resultsstart()
{
for (int i=0; i<9; i++)
{
int num=getnum(i);
bfs(num,i,i);
}
}
int main()
{
resultsstart();
int t;
scanf("%d%*c",&t);
for (int i=1; i<=t; i++)
{
int v;
scanf("%s%*c",endresult[10]);
scanf("%s%*c",endresult[11]);
int num=1;
for (int j=0; j<9; j++)
{
if (endresult[10][j]=='X')
{
v=j;
endresult[10][j]='0';
}
else
{
mapping[endresult[10][j]-'0']='0'+num;
endresult[10][j]='0'+num;
num++;
}
}
for (int j=0; j<9; j++)
{
if (endresult[11][j]=='X')
{
endresult[11][j]='0';
}
else
{
endresult[11][j]=mapping[endresult[11][j]-'0'];
}
}
int arrange=getnum(11);
int ansnum=0;
stack<char>zhanans;
while (1)
{
if (p[v][arrange].from==-1)
{
break;
}
zhanans.push(dic[p[v][arrange].opt]);
arrange=p[v][arrange].from;
ansnum++;
}
printf("Case %d: %d\n",i,ansnum);
while (!zhanans.empty())
{
char ansc=zhanans.top();
zhanans.pop();
printf("%c",ansc);
}
printf("\n");
}
}