松下問童子,言師採藥去。
只在此山中,雲深不知處。——賈島ios
網址:https://www.luogu.com.cn/problem/P2730編程
這是一張有8個大小相同的格子的魔板:數組
1 2 3 4編碼
8 7 6 5spa
咱們知道魔板的每個方格都有一種顏色。這8種顏色用前8個正整數來表示。能夠用顏色的序列來表示一種魔板狀態,規定從魔板的左上角開始,沿順時針方向依次取出整數,構成一個顏色序列。code
對於上圖的魔板狀態,咱們用序列(1,2,3,4,5,6,7,8)來表示。
這是基本狀態。ip
這裏提供三種基本操做,分別用大寫字母「A」,「B」,「C」來表示(能夠經過這些操做改變魔板的狀態):字符串
「A」:交換上下兩行;get
「B」:將最右邊的一列插入最左邊;string
「C」:魔板中央四格做順時針旋轉。
下面是對基本狀態進行操做的示範:
A: 8 7 6 5
1 2 3 4
B: 4 1 2 3
5 8 7 6
C: 1 7 2 4
8 6 3 5
對於每種可能的狀態,這三種基本操做均可以使用。
你要編程計算用最少的基本操做完成基本狀態到目標狀態的轉換,輸出基本操做序列。
只有一行,包括8個整數,用空格分開(這些整數在範圍 1——8 之間)不換行,表示目標狀態。
Line 1: 包括一個整數,表示最短操做序列的長度。
Line 2: 在字典序中最先出現的操做序列,用字符串表示,除最後一行外,每行輸出60個字符。
2 6 8 4 5 7 3 1
7 BCABCCB
選自USACO Training Section 3.2
作完八數碼問題,不難理解這道題能夠使用廣搜解決(畢竟時間複雜度與八數碼問題相似)。
像以前的八數碼問題同樣,咱們把狀態定義成一個八位數,代碼中簡單的使用STL中map和set進行記錄與判重。
代碼以下:
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<queue> #include<map> #include<set> using namespace std; const int rot[4] = {2, 1, 5, 6}; int st = 12348765, ed = 0, s[10]; map <int, int> d, f; set <int> vis; void decode(int state, int *p) { for(int i = 7; i >= 0; -- i) { p[i] = state % 10; state /= 10; } //將十進制編碼轉化爲數組 return; } int encode(int *p) { int cnt = 0; for(int i = 0; i < 8; ++ i) { cnt = (cnt << 1) + (cnt << 3) + p[i]; } //將數組轉化爲十進制8位編碼 return cnt; } void flip(int cur, int *p) { switch(cur) { case 0 : { for(int i = 0; i < 4; ++ i) { swap(p[i], p[i + 4]); } break; } case 1 : { for(int i = 2; i > -1; -- i) { swap(p[i], p[i + 1]); swap(p[i + 4], p[i + 5]); } break; } case 2 : { for(int i = 0; i < 3; ++ i) { swap(p[rot[i]], p[rot[i + 1]]); } break; } } return; } void print_ans(int state) { if(state == st) return; int prev_state = 0; decode(state, s); switch(f[state]) { case 0: { for(int i = 0; i < 4; ++ i) { swap(s[i], s[i + 4]); } break; } case 1: { for(int i = 0; i < 3; ++ i) { swap(s[i], s[i + 1]); swap(s[i + 4], s[i + 5]); } break; } case 2: { for(int i = 2; i >= 0; -- i) { swap(s[rot[i + 1]], s[rot[i]]); } break; } } for(int i = 0; i < 8; ++ i) { prev_state = prev_state * 10 + s[i]; } memset(s, 0, sizeof(s)); print_ans(prev_state); printf("%c", f[state] + 'A'); return; } void bfs() { //特判 初始狀態 和 目標狀態 相同 if(st == ed) { puts("0"); return; } f.clear(), vis.clear(); queue <int> Q; while(!Q.empty()) Q.pop(); Q.push(st); vis.insert(st); int copy[8] = {}, now, next; while(!Q.empty()) { now = Q.front(); Q.pop(); decode(now, s); memcpy(copy, s, sizeof(copy)); for(int i = 0; i < 3; ++ i) { flip(i, s); next = encode(s); memcpy(s, copy, sizeof(s)); if(vis.count(next)) continue; d[next] = d[now] + 1; f[next] = i; if(next == ed) { printf("%d\n", d[next]); print_ans(next); return; } Q.push(next); vis.insert(next); } } return; } int main() { memset(s, 0, sizeof(s)); for(int i = 0; i < 4; ++ i) scanf("%d", &s[i]); //目標狀態處理: for(int i = 7; i >= 4; -- i) scanf("%d", &s[i]); //留意陷阱呢 for(int i = 0; i < 8; ++ i) { ed = (ed << 1) + (ed << 3) + s[i]; } bfs(); return 0; }