1. 程式人生 > >hdu1584蜘蛛牌解題報告---搜尋(深搜 & 回溯)

hdu1584蜘蛛牌解題報告---搜尋(深搜 & 回溯)

                                                 蜘蛛牌

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6100    Accepted Submission(s): 2546

Problem Description

蜘蛛牌是windows xp作業系統自帶的一款紙牌遊戲,遊戲規則是這樣的:只能將牌拖到比她大一的牌上面(A最小,K最大),如果拖動的牌上有按順序排好的牌時,那麼這些牌也跟著一起移動,遊戲的目的是將所有的牌按同一花色從小到大排好,為了簡單起見,我們的遊戲只有同一花色的10張牌,從A到10,且隨機的在一行上展開,編號從1到10,把第i號上的牌移到第j號牌上,移動距離為abs(i-j),現在你要做的是求出完成遊戲的最小移動距離。

Input

第一個輸入資料是T,表示資料的組數。
每組資料有一行,10個輸入資料,資料的範圍是[1,10],分別表示A到10,我們保證每組資料都是合法的。

Output

對應每組資料輸出最小移動距離。

Sample Input

1

1 2 3 4 5 6 7 8 9 10

Sample Output

9

很有價值的一道全排列搜尋,既要考慮回溯的位置,又要處理每張牌的移動情況

 AC Code:

#include <cstdio>
#include <cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<map>
#include<queue>
#include<climits>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;
typedef long long ll;
static const int MAX_N = 1e6 + 5;
bool vis[12];
int vv[12];
int res;
void dfs(int step, int sum){
    if(step == 9){
        res = min(res, sum);
        return;
    }
    if(step > 9) return;
    for(int i = 1; i < 10; i++){
        if(vis[i]) continue;
        vis[i] = true;      //移動面值為i的牌
        for(int j = i + 1; j <= 10; j++){
            if(vis[j]) continue;  
//說明面值為i + 1的牌已經擺在更大面值牌的下面了,把i放在這張更大面值的牌j下面
            dfs(step + 1, sum + abs(vv[i] - vv[j]));
            break;  //找到這張最大面值牌後跳出迴圈
        }
        vis[i] = false; //回溯要放這裡
    }
}
int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        res = 9999;
        for(int i = 1; i <= 10; i++){
            int v;
            scanf("%d", &v);
            vv[v] = i;  //面值為v的牌的位置
        }
        dfs(0, 0);
        printf("%d\n", res);
    }
    return 0;
}