UVA 11212 Editing a Book 【IDA*】

題目鏈接

題意

給一個n個數的全排列,可以進行將任意連續的一段截下來插入到任意位置的操作,問至少需要多少步這樣的操作能夠是序列變成遞增的序列。

分析

題中n的最大值爲9,狀態數爲9的階乘,不過1e6左右,看似可以直接BFS。但是每一種狀態後的決策數量太多了(任意位置的任意長度再插入到任意位置)
考慮到n個數的全排列,要使之恢復遞增的順序,最多移動n-1次即可。這樣層數有上限,嘗試用DFS。然而直接DFS回溯次數太多了,於是考慮使用IDA*。

尋找樂觀估價函數,也就要尋找一個指標來反應這個序列有多“接近”單調遞增。我們直接統計後繼不正確的數的個數,如2,1,3,4中2和1的後繼都不正確,所以不正確數爲2。考慮每一步是把一個區間移到另一個位置,每次最多隻會改變三個位置的後繼。易知遞增序列的後繼不正確數爲0,因此設後繼不正確數爲h,則樂觀估價函數爲g(h)=h/3 ,所以當3d+h>3maxd 時剪枝

注意此題有可能本身給的串就是遞增的,所以DFS層數應該從0開始,這樣就不會遺漏這種情況

AC代碼

//UVA 11212 Editing a Book
//AC 2016-7-25 18:36:25
//IDA*
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <list>
#include <sstream>
#include <stack>
using namespace std;

#define cls(x) memset(x,0,sizeof x)
#define inf(x) memset(x,0x3f,sizeof x)
#define neg(x) memset(x,-1,sizeof x)
#define ninf(x) memset(x,0xc0,sizeof x)
#define st0(x) memset(x,false,sizeof x)
#define st1(x) memset(x,true,sizeof x)
#define INF 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define bug cout<<"here"<<endl;
//#define debug

int maxd=9;
vector<int> org;

vector<int> moveto(const vector<int> &opr,int beg,int endd,int pos)
{
    vector<int> temp;
    for(int i=0;i<pos;++i)
        temp.push_back(opr[i]);
    for(int i=beg;i<=endd;++i)
        temp.push_back(opr[i]);
    for(int i=pos;i<beg;++i)
        temp.push_back(opr[i]);
    for(int i=endd+1;i<opr.size();++i)
        temp.push_back(opr[i]);
    return temp;
}

bool DFS(int d,vector<int> seq)
{
    int h=0;
    for(int i=0;i<seq.size()-1;++i)
        if(seq[i]+1!=seq[i+1])
            ++h;
    //for(int i=0;i<seq.size();++i)
        //cout<<seq[i]<<" ";
    //cout<<h<<"---"<<d<<"**"<<maxd<<endl;
    //getchar();
    if(d==maxd)
        return !h;
    if(3*d+h>3*maxd)
        return false;
    bool res=0;
    for(int i=1;i<seq.size();++i)
        for(int j=i;j<seq.size();++j)
            for(int k=0;k<=i-1;++k)
                if(DFS(d+1,moveto(seq,i,j,k)))
                    return true;
    return false;
}

int IDA_star()
{
    for(maxd=0;maxd<=org.size();++maxd)
        if(DFS(0,org))
            return maxd;
}

int main()
{
    #ifdef debug
        freopen("E:\\Documents\\code\\input.txt","r",stdin);
        freopen("E:\\Documents\\code\\output.txt","w",stdout);
    #endif
    int n,a,cnt=1;
    while(cin>>n&&n)
    {
        org.clear();
        while(n--)
        {
            cin>>a;
            org.push_back(a);
        }
        printf("Case %d: %d\n",cnt++,IDA_star());
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章