1. 程式人生 > 實用技巧 >Acwing 181 迴轉遊戲 (IDA*)

Acwing 181 迴轉遊戲 (IDA*)

題面

如下圖所示,有一個“#”形的棋盤,上面有1,2,3三種數字各8個。

給定8種操作,分別為圖中的A~H。

這些操作會按照圖中字母和箭頭所指明的方向,把一條長為8的序列迴圈移動1個單位。

例如下圖最左邊的“#”形棋盤執行操作A後,會變為下圖中間的“#”形棋盤,再執行操作C後會變成下圖最右邊的“#”形棋盤。

給定一個初始狀態,請使用最少的操作次數,使“#”形棋盤最中間的8個格子裡的數字相同。

2286_1.jpg

輸入格式
輸入包含多組測試用例。

每個測試用例佔一行,包含24個數字,表示將初始棋盤中的每一個位置的數字,按整體從上到下,同行從左到右的順序依次列出。

輸入樣例中的第一個測試用例,對應上圖最左邊棋盤的初始狀態。

當輸入只包含一個“0”的行時,表示輸入終止。

輸出格式
每個測試用例輸出佔兩行。

第一行包含所有移動步驟,每步移動用大寫字母“A~G”中的一個表示,字母之間沒有空格,如果不需要移動則輸出“No moves needed”。

第二行包含一個整數,表示移動完成後,中間8個格子裡的數字。

如果有多種方案,則輸出字典序最小的解決方案。

輸入樣例:
1 1 1 1 3 2 3 2 3 1 3 2 2 3 1 2 2 2 3 1 2 1 3 3
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
0
輸出樣例:
AC
2
DDHH
2

思路

搜尋,問最小步數,可以想到bfs和ida,那麼我們考慮使用ida

,首先的話為了方便我們可以打表然後把二維壓成一維去操作,這樣比較方便。那麼我們這裡考慮一下估價函式,目的是要中央那一圈數字一樣,我們進行一次操作會出圈一個數,進圈一個數,那麼這樣的話我們考慮最優情況,最終狀態是原先數字最多的,那麼我們可以用最少的運算元得到結果,所以估價函式為8-最多的數字的數量,然後就直接寫ida的框架就好了。這裡總結一個ida,總而言之最重要的還是一個估價函式的設計,估價函式怎麼尋找,我們要儘量去往操作對最終結果的影響上去想,然後取一個最優的情況做為估價函式就好了。

程式碼實現

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#include<stack>
using namespace std;
const int maxn=24;
int option[8][7] {
    {0,2,6,11,15,20,22},
    {1,3,8,12,17,21,23},
    {10,9,8,7,6,5,4},
    {19,18,17,16,15,14,13},
    {23,21,17,12,8,3,1},
    {22,20,15,11,6,2,0},
    {13,14,15,16,17,18,19},
    {4,5,6,7,8,9,10}
};
int opposite[8]={5,4,7,6,1,0,3,2};
int center[8]={6,7,8,11,12,15,16,17};

int q[maxn];
int path[100];

int f () {
    static int sum[4];
    memset (sum,0,sizeof (sum));
    for (int i=0;i<8;i++) {
        sum[q[center[i]]]++;
    }
    int s=0;
    for (int i=1;i<=3;i++) {
        s=max (s,sum[i]);
    }
    return 8-s;
}

bool check () {
    for (int i=0;i<8;i++) 
      if (q[center[i]]!=q[center[0]]) return false;
    return true;
}

void oper (int x) {
   int t=q[option[x][0]];
   for (int i=0;i<6;i++) q[option[x][i]]=q[option[x][i+1]];
   q[option[x][6]]=t;
}

bool dfs (int deep,int maxdeep,int last) {
    if (deep+f()>maxdeep) return false;
    if (check ()) return true;

    for (int i=0;i<8;i++) {
        if (opposite[i]==last) continue;
        oper (i);
        path[deep]=i;
        if (dfs (deep+1,maxdeep,i)) return true;
        oper (opposite[i]);
    }
    return false;
}

int main () {
    while (cin>>q[0]&&q[0]) {
        for (int i=1;i<maxn;i++) {
            cin>>q[i];
        } 
    int deepth=0;
    while (!dfs (0,deepth,-1)) deepth++;
    if (!deepth) cout<<"No moves needed";
    else {
      for (int i=0;i<deepth;i++) printf ("%c",path[i]+'A');
    }
    printf ("\n%d\n",q[6]);
   }
    return 0;
}