題解西電OJ (Problem 1006 - 轉盤遊戲)--動態規劃

 

題目連接 : http://acm.xidian.edu.cn/land/problem/detail?problem_id=1006node

 

Description算法

 

  wm最近喜歡上一種無聊的轉盤解鎖遊戲,他天天都會爲這遊戲消磨上三個小時的時間。這遊戲由三個正六邊形拼成,拼成後一共有13個點,其中有4個黑點和9個白點,以下圖。每一步能夠順時針或逆時針轉動三個六邊形的任意一個60度,轉動時六邊形的頂點也會相應轉動,而這遊戲的目的是把四個黑點都轉到中間(圖中最後一個狀態)。這是一個很簡單的遊戲,想達到遊戲目的並不難,但wm以爲這樣沒挑戰性,他決定對於任意一個初始狀態,用最少的步數去玩這個遊戲。app

 

Input

 

  輸入包含多組數據(500組),EOF結束。
每組數據都只有一行13個字符的01串,以從上到下,從左到右的點的順序表示初始狀態(這個由三個正六邊形拼成圖形最上面一排兩個點編號爲1 2,第二排三個點編號爲3 4 5,依此類推,最後一個點編號爲13。第一組樣例爲上圖的初始狀態),其中1表示黑點0表示白點。

 

Output

 

  每組數據輸出一行,解出遊戲須要的最小步數。

 

Sample Input

 

0000000101011
1011000001000

 

Sample Output

 

3
2

 

 

 

 

 

題解:

 

每一個六邊形,能夠朝兩個方向旋轉,共有3個六邊形,共每一個狀態能夠變化到其餘六個狀態。

 

假設初始狀態是S,剩下變換後的六個狀態分別是S1, S2, S3, S4, S5, S6 。

 

一個狀態最快旋轉獲得指望結果的最小次數假定是 Res[S], 那麼有如下結論:

 

Res[S] = min{Res[S1], Res[S2],Res[S3],Res[S4], Res[S5],Res[S6]}  +  1  ;

 

那麼這個問題變得簡單了,其實就是一個遞歸能夠解決的問題。可是這不是ACM的精神,由於這個方法不是最優的,想一想哪裏能夠優化,

 

遞歸的方法會出現大量的重複計算,由於S狀態執行3次S1 和 執行3次S2後會獲得相同的狀態,爲了不這種重複的計算咱們採用動態規劃算法。

 

初始狀態是指望的結果S=0x348 (二進制爲  0001101001000),0標示白色,1標示黑色,上圖中1序號位置對應的2進制數字的最低位,依次類推。

 

初始的Res[0x348] = 0 ;

 

初始狀態S[0] = 0x348 ;

 

而後分別計算,從S[0] 通過1次變換可獲得的6種狀態,這六種狀態的Res爲1,而後依次計算, 狀態的最大數是0x1E00 (二進制爲1111000000000)

 

 

 

附上代碼實現:

 

 1 #include "stdio.h"
 2 
 3 // change status
 4 int turn(int status,int op)
 5 {
 6     static int ops[6][6]={ 
 7         {0, 2, 5, 8, 6, 3}, {0, 3, 6, 8, 5, 2},
 8         {1, 3, 6, 9, 7, 4},    {1, 4, 7, 9, 6, 3},
 9         {6, 8, 10, 12, 11, 9}, {6, 9, 11, 12, 10, 8}};
10 
11 
12     //// trans status to node status
13     int node[13]={} ;
14     int tmp , i ;
15     for(i = 0 ; status ; status>>=1) {
16         node[i++] = status & 1 ;
17     }
18     //// do operation , and get res
19     
20     for(tmp = node[ops[op][i=0]]; i < 5 ; i++){
21         node[ops[op][i]] = node[ops[op][i+1]] ;
22     }
23     node[ops[op][5]] = tmp ;
24     for(i = 0 ; i < 13 ; i++){
25         status |= node[i]<<i ;
26     }
27     return status ;
28 }
29 
30 
31 
32 int main()
33 {
34     ///// the max number status is 1111000000000 , is 0x1E00
35     int status[int(0x1E01)] = {} ;
36     int res[int(0x1E01)] = {} ;
37     ///// final status is 0001101001000 , is 0x348
38     res[int(0x348)] = 0 ;
39     status[0] = 0x348 ;
40     int s_sum = 1 ;
41     int i , j ;
42     char str[13] = {};
43     ///// Cal the res array
44     for(i = 0 ; i < s_sum ; i++){
45         for(j = 0 ; j < 6 ; j++){
46             int next_s = turn(status[i],j);
47             if(res[next_s]<=0){
48                 res[next_s] = res[status[i]] + 1 ;
49                 status[s_sum++] = next_s ;
50             }
51         }
52     }
53     ///output answer
54     for(;scanf("%s",str)!=EOF;printf("%d\n",res[j])){
55         for(i = 0 , j = 0 ; i < 13 ; i++){
56             j |= (str[i]-'0')<<i ;
57         }
58     }
59     return 0;
60 }
相關文章
相關標籤/搜索