by medalplus
題目描述
在3×3的棋盤上,擺有八個棋子,每個棋子上標有1至8的某一數字。棋盤中留有乙個空格,空格用0來表示。空格周圍的棋子可以移到空格中。要求解的問題是:給出一種初始布局(初始狀態)和目標布局(為了使題目簡單,設目標狀態為123804765),找到一種最少步驟的移動方法,實現從初始布局到目標布局的轉變。
輸入格式
輸入初試狀態,一行九個數字,空格用0表示
輸出格式
只有一行,該行只有乙個數字,表示從初始狀態到目標狀態需要的最少移動次數(測試資料中無特殊無法到達目標狀態資料)
分析
其實就是個裸的bfs,但是可以拓展很多知識點(有人說不做這題的人的oi人生不完美)
暴力bfs的話會被卡,因為要搜尋的狀態實在太多了
所以這裡有兩種優化:
1.啟發式搜尋
我們假設f=g+h,那麼g可以設為已經挪動的步數,h為不在位將牌個數,這樣就構建了乙個估價函式
然後直接寫就好
2.雙向bfs
我們知道起點和終點,直接雙向就好
另外,這裡應該如何判重呢?其實很簡單,下面引入康托展開:
然後就利用康托值進行判重就好
**
1 #include 2 #include 3 #include 4 #include 5using
namespace
std;67
#define rep(i,l,r) for(i=l;i<=r;i++)
8const
int maxn=10;9
const
int maxm=1000001;//
9!*8+8!*7...<=5000001
1011
struct
node
15}head,tail;
1617
short
intvis_f[maxm],vis_b[maxm];
18int
tmps[maxn];
19 queuef,b;
2021
int fact(int
x)26
27int cantor(node now)
41return
res;42}
4344
void
init_front()
5051
void
init_back()
5758
void
init()
6465
void
expand_f()
78 tmp=head;
79if(sx-1>0)83
if(vis_f[cantor(tmp)]==-1)87
}88 tmp=head;
89if(sx+1
<=3)93
if(vis_f[cantor(tmp)]==-1)97
}98 tmp=head;
99if(sy-1>0
)103
if(vis_f[cantor(tmp)]==-1
)107
}108 tmp=head;
109if(sy+1
<=3
)113
if(vis_f[cantor(tmp)]==-1
)117
}118
}119
120void
expand_b()
133 tmp=head;
134if(sx-1>0
)138
if(vis_b[cantor(tmp)]==-1
)142
}143 tmp=head;
144if(sx+1
<=3
)148
if(vis_b[cantor(tmp)]==-1
)152
}153 tmp=head;
154if(sy-1>0
)158
if(vis_b[cantor(tmp)]==-1
)162
}163 tmp=head;
164if(sy+1
<=3
)168
if(vis_b[cantor(tmp)]==-1
)172
}173
}174
175void
double_bfs()
185else
189}
190}
191192
intmain()
**量比較大,竟然有個小200....
洛谷OJ P1379 八數碼難題(雙向搜尋)
思路 相信不少小夥伴上來就是暴力dfs,但是拿到題之後我們不妨想一想如果純dfs爆搜下來會產生多少種狀態,這樣的方法是否是最優的?這裡選擇使用一種稱之為雙向搜尋的方法 通過知乎學到的,放出來share一下 具體來說就是若已知初始狀態和終止狀態下我們同時從起點和終點開始dfs 當然也有bfs寫法,這裡...
洛谷 1379 八數碼難題
題目 八數碼難題 思路 bfs hash判重。注意 1 hash的鍊錶不能寫錯。2 由於用的是一位陣列,所以移動時要判斷左右邊界。比如當前的空位在5處,就不能向右移 1。0 1 2 3 4 5 6 7 8 include include include include include include...
洛谷 1379 八數碼難題
在3 3的棋盤上,擺有八個棋子,每個棋子上標有1至8的某一數字。棋盤中留有乙個空格,空格用0來表示。空格周圍的棋子可以移到空格中。要求解的問題是 給出一種初始布局 初始狀態 和目標布局 為了使題目簡單,設目標狀態為123804765 找到一種最少步驟的移動方法,實現從初始布局到目標布局的轉變。輸入格...