太感人了,错了一天看了一天,终于AC了!
仿佛人生度过了几个轮回呜呜呜
这题,看题解都是双向BFS,因为双向比单向快了好多
双向,说白就是一键双开,让你在开前面的时候顺便开后面,用两个队列也行,一个队列更好写,因为你得开完两个队列前面一层再开后面一层,你只要用一个
flag标记一下前后即可
1.
然后正向与反向有什么区别呢,正向遇到反向的最小,才是最小,而反向的最小遇到正向,此时不一定是最小
例如题目的顺序是 dlru
那么你两边都是从dlru那么走,
假设你的后面走了dl 忽然发现前面有一个u刚好可以,那你就直接 udl输出
而实际上 后面来的 ul 哭了 ,它遇到了 d 是 dul 为啥子它比较小反而不行,那怎么办呢,只能后面的时候只储存就好啦,反正正向迟早可以找到自己的!省的闹麻烦勒
还有一件事,后面走的,,如果 你先来一个 ud ,后面 来了一个 du ,你和它走到了相同的位置, 不就很尴尬? 所以你必须要比较一下谁大谁占坑!顺便别忘了把 du 也队列放进去跑哦
2.
接下来比较不会考虑的是存储路经
用string 感觉太大,所以采用4进制的long long 来存储,但又有一个问题,如果它一直走d,不就一直0?所以为了防止漏0,俺先给它赋值为1
正向直接就 (4进制表示) 1->10->103->1032
反向为了防止比较大小的时候出错,所以把它采用正向储存,用了一个path数组来储存4进制进位,其就为 1 -> 13 -> 123 -> 1023 这个样子
在方向的时候需注意:反向走dlru的时候 下则要走上!左则要走右!为了走dlru,所以写了 3-i
3.
map<string, long long> 会炸TLE
map<long long , long long> 不会
4.
第一步要注意不用乱把不该放的放进去 不然你可能会 MLE
代码如下
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <string>
#include <cstring>
#include <map>
using namespace std;
string be,en; //储存开始序列和结束序列
long long s1,s2;//存正向和反向要输出的
char ss[1000];//用于输出
int dis[4][2]= { {1,0},{0,-1},{0,1},{-1,0} }; //dlru正 反ulrd
char c[]="dlru";
long long path[100];//存储4进制
long long pu(string s)//将序列化为数字存储状态
{
long long sum = 0;
int n = s.size();
for (int i = 0; i < n; i++)
{
sum = sum*10+((s[i] == 'X')?0:s[i]-'0');
}
return sum;
}
struct stu{
long long wei;//储存已经走的路劲
int flag; //正反
string S; //目前队列
int bu; //已走步数
};
map <long long , long long> C,C1; // 状态存储 顺便路劲储存
void BFS()
{
C.clear(); C1.clear(); //初始化
if(be == en) return ; //一样的情况
stu Be,Nex,En;
long long s = pu(be); C[s] = 1;
Be.wei = 1; Be.flag = 0; Be.S = be;
s = pu(en); C1[s] = 1;
En.wei = 1; En.flag = 1; En.S = en;
Be.bu = 0; En.bu = 0;
queue <stu> q;
q.push(Be); q.push(En);
while( !q.empty() ){
Be = q.front(); q.pop();
int W = 0;
for (int i = 0; i < 9; i++)
if(Be.S[i] == 'X') { //找到0 的位置
W = i; break;
}
int x = W/3, y = W%3;
for (int i = 0; i < 4; i++){
Nex = Be; Nex.bu++; // 先加一步
int newx,newy;
if(!Be.flag) //为了走dlru
{
newx = x + dis[i][0],newy = y + dis[i][1];
}
else{
newx = x + dis[(3-i)][0],newy = y + dis[(3-i)][1]; //3-i
}
int newW = newx*3 + newy;
if(newx >= 0 && newx < 3 && newy >= 0 && newy < 3 ){
swap(Nex.S[W],Nex.S[newW]);
long long s = pu(Nex.S);
if(!Be.flag && !C.count(s)){
Nex.wei = Nex.wei*4 + i; //推的
C[s] = Nex.wei;
if(C1.count(s)){
s1 = C[s]; s2 = C1[s];
return;
}
q.push(Nex);
}
else if( Be.flag ){
Nex.wei = Nex.wei-path[Be.bu]*1 + i*path[Be.bu] + 1*path[Nex.bu];//推的
if(!C1.count( s )){
C1[ s ] = Nex.wei; q.push(Nex);
}
else{
if( C1[s] > Nex.wei ) {
C1[s] = Nex.wei;
q.push(Nex);
}
}
/*if(C.count((Nex.S))){
s1 = C[Nex.S]; s2 = C1[Nex.S];
return;
}*///没有权力,只能等人拯救
}
}
}
}
}
int main()
{
int n; int k = 1;
for (int i = 0; i < 30;i++)
{
path[i] = k;
k*=4;
}//将四进制阶数求出
scanf("%d",&n);
for (int i = 0; i < n; i++)
{
memset(ss,0,sizeof(ss));
int mm = 0;
cin >> be >> en; s1 = 1; s2 = 1;
BFS();
//十进制转四进制
while(s1!=1 && s1>0){
int k = s1%4;
ss[mm++] = c[k];
s1/=4;
}
for (int j = 0; j < mm/2; j++){
char t = ss[j]; ss[j] = ss[mm-j-1];
ss[mm-j-1] = t;
}
int zz = mm;
while(s2!=1 && s2>0){
int k = s2%4;
ss[mm++] = c[k];
s2/=4;
}
printf("Case %d: %d\n",i+1,mm);
for (int i = 0; i < zz; i++){
printf("%c",ss[i]);
}
for (int i = mm-1; i >= zz; i--){
printf("%c",ss[i]);
}
printf("\n");
}
}