poj 3460 IDA*

题意:有n (n<=15) 本高度不同的书,每次可以交换相邻的两部分书(多本),问最少多少次操作可以让书由小到大排列?如果次数>=5  输出5 or more,否则输出最少次数。

分析:n!的状态空间太大,不能广搜,于是想到迭代加深搜索,又因为每次操作,最多改变3个后继值,最终状态每本书的后继都比自身大1,可以设计启发函数为 错误的后继值/3.

另外在回溯的时候,假设本次交换的区间为[1,5]  [6,8]那么还原状态应该交换[1,3]  [4,8],而不能再次交换[1,5]  [6,8]。。

          1 2 3 4 5|6 7 8

交换[1,5] [6,8]:  6 7 8|1 2 3 4 5

交换[1,3] [4,8]:  1 2 3 4 5|6 7 8

 

 

int lim;
int n,ans;
int a[20];

inline int h(){
    int cnt=0;
    FOR(i,0,n-1) if(a[i]+1!=a[i+1]) cnt++;
    return (cnt+2)/3;
}

//void print(){ FOR(i,0,n)cout<<a[i]<<' ';cout<<endl; }

inline void Swap(int x,int y,int p,int q){         //if(lim==2) {cout<<x<<' '<<y<<' '<<p<<' '<<q<<' '<<lim<<' '<<endl;print();}
    int t1=(y-x+1)>>1, t2=(q-p+1)>>1, t3=(q-x+1)>>1;
    FOR(i,0,t1){ swap(a[x+i],a[y-i]); }
    FOR(i,0,t2){ swap(a[p+i],a[q-i]); }
    FOR(i,0,t3){ swap(a[x+i],a[q-i]); }           //if(lim==2){  print();cout<<endl;}
}

void IDA_Star(int s){
    int H=h();                  //if(lim==2)    cout<<i<<' '<<H<<' '<<lim<<endl;
    if(H==0){ans=s;return;}
    else if(s+H>lim)return;

    FOR(i,0,n-1) FOR(j,i+1,n) FOR(k,i,j){    if(ans!=-1)return;
        Swap(i,k,k+1,j);
        IDA_Star(s+1);
        Swap(i,j-k+i-1,j-k+i,j);
    }
}

int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    #endif

    int T;
    cin>>T;
    while(T--){
        cin>>n;
        FOR(i,0,n)cin>>a[i];
        ans=-1;

        lim=h();
        while(lim<=4 && ans==-1){
            IDA_Star(0);
            lim++;
        }

        if(ans==-1)cout<<"5 or more"<<endl;
        else cout<<ans<<endl;
    }

    return 0;
}

 

转载于:https://www.cnblogs.com/ts65213/archive/2013/05/11/3072577.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值