1. 程式人生 > >Sicily 1142. Pancake Sorting(煎餅排序)

Sicily 1142. Pancake Sorting(煎餅排序)

題目大意:煎餅排序。

這個問題是Bill Gates想出來的。描述如下。

一位餐廳侍者在送出一疊煎餅 (pancakes) 到顧客之前,發現廚師實在太困了,這些煎餅大小不一,混雜在一起堆成一疊,客人實在不會有太多好感。因此,在送出這些煎餅之前,這位侍者會使用一片鍋鏟將這些煎餅重新排成一疊由小而大排列的煎餅。不過,由於盤子太小,我們不能夠將煎餅平鋪後再重新排一次,而只能用鍋鏟卡在某個煎餅的下方,將上頭全部的煎餅一起做翻面的動作。比如說,這裡有三塊煎餅,最大的一塊叫做3,中間大小的是2,最小的一塊就是1。如果1號在盤子的最下面,3號煎餅疊在它上面,最上面的煎餅就是2號;由上而下的排列就是:(2,3,1)。那麼,侍者就可以先用鍋鏟卡在第二個煎餅的下方,將前2個煎餅做翻面的動作,這三個煎餅順序就成了:(3,2,1);然後,侍者就可以再用鍋鏟卡在第3個煎餅的下方,將全部煎餅做翻面的動作,這三個煎餅順序就成了:(1,2,3)。好了,我們這位高興的侍者就可以趕緊將這些排好的煎餅送出去給客人了。

解題思路:

1.當然可以進行裸深搜,但是想不出剪枝的方法,可能TLE所以沒進行嘗試。

2.迭代深搜。在深搜之前預測一個搜尋深度最小值,搜尋深度不超過這個值。如果找到返回,如果找不到增加搜尋深度。

資料結構:index[],num[]

index為num索引,目的將輸入數字對映成0,1,2,3,4...n

主要函式:

1.bool comp()。 通過num大小對index進行排序。

如實際輸入為6,8,2,4,排序後的index為3,2,1,4。

將index排序為1,2,3,4次數相當於將實際輸入排序還原為6,8,2,4。

從6,8,2,4到2,4,6,8和從2,4,6,8到6,8,2,4排序次數相同。

2.inline int dfs_depth()。 得到一個預期搜尋深度的最小值。即最小交換次數。

當相鄰兩數差值絕對值大於1時,至少需要交換一次才可以完成排序。

計算有多少對相鄰數差值絕對值大於1,得到初始搜尋深度。

3.bool dfs( int depth )。迭代深搜。

// 1142. Pancake Sorting(煎餅排序) 

#include <cstdio>  
#include <cmath>
#include <algorithm>  

using namespace std;  

// index為num建立索引 
int n,index[26],num[26];

inline bool isFinished();                   // 判斷是否完成排序 
inline int dfs_depth();                     // 得到至少交換次數,才能完成排序 
bool comp( const int& a, const int& b );    
bool dfs( int depth );

int main(){

    scanf("%d",&n);   
    for( int i = 0; i < n; ++i ){
        index[i] = i;
        scanf("%d",num+i);        
    }
    sort( index, index+n, comp ); 
    
    int cnt = dfs_depth();      
    // 如果當前深度不滿足排序,則增加搜尋深度。  
    while( !dfs( cnt++ ) ){}
    
    printf("%d\n",cnt-1); 
    
    return 0;    
}

bool comp( const int&a, const int& b ){
    return num[a] < num[b];    
}

inline bool isFinished(){
    for( int i = 0; i < n - 1; ++i ){
        if( index[i] > index[i+1] ) return false;    
    } 
    return true;   
} 

inline int dfs_depth(){
    int depth = 0;
    for( int i = 0; i < n - 1; ++i ){
        // 如果相鄰的值差值大於1,那麼必須進行一次交換
        // 差值為1可以在其他交換時,同時進行交換 
        depth += ( fabs( float(index[i] - index[i+1]) ) > 1 );    
    }     
    return depth;
} 

bool dfs( int depth ){
    // depth為0表示序列不存在差值大於1的相鄰數,則判斷是否有序 
    if( depth == 0 ){
        if( isFinished() ) return true;
        else return false;    
    }
    // 排序次數必須大於最少交換次數 
    if( depth < dfs_depth() ) return false;
    
    for( int i = 2; i <= n; ++i ){
        reverse( index, index+i );          
        if( dfs(depth-1) ) return true;
        reverse( index, index+i );  // 如果當前狀態無法得到結果,則返回初始序列 
    }
    return false;
}