太感人了,錯了一天看了一天,終於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");
}
}