UVA - 11212 Editing a Book

题目链接

大致就是给一个1到n的数字组成的乱序数组,问最少剪贴黏贴几次能把它变成一个1到n升序的数组。

用IDA* 不正确的数字个数为h 则每个深度h最多减少3(后接数字变化的三个数都对上,减少三) 则3d+h>3maxd就剪枝(当前操作方法减少的不正确数超过最多不正确数)

这道题枚举剪切黏贴的方法很值得学习

AC代码:

/*#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int n,a[10];

bool ans_sort()
{
    for(int i=0;i<n-1;i++)
        if(a[i]>=a[i+1]) return false;
    return true;
}
int h()
{
    int cnt=0;
    for(int i=0;i<n-1;i++)
        if(a[i]+1!=a[i+1]) cnt++;
    if(a[n-1]!=n)cnt++;
    return cnt;
}
bool dfs(int d,int maxd)
{
    if(d*3+h()>=maxd*3) return false;
    if(ans_sort()) return true;
    int o[10],b[10];
    memcpy(o,a,sizeof(a));
    for(int i=0;i<n;i++)
    {
        for(int j=i;j<n;j++)
        {
            int cnt=0;
            for(int k=0;k<n;k++)
                if(k<i||k>j)b[cnt++]=a[k];
            for(int k=0;k<=cnt;k++)
            {
                int cnt2=0;
                for(int p=0;p<k;p++) b[cnt2++]=b[p];
                for(int p=i;p<=j;p++)a[cnt2++]=o[p];
                for(int p=k;p<cnt;p++)a[cnt2++]=b[p];

                if (dfs(d+1,maxd)) return true;
                memcpy(a,o,sizeof(a));
            }
        }
    }
    return false;
}
int solve()
{
    int max_ans=8;
    for(int maxd=1;maxd<8;maxd++)
        if(dfs(0,maxd))return maxd;

    return max_ans;
}
int main()
{
    int kase=0;
    while(cin>>n&&n)
    {

        for(int i=0;i<n;i++) cin>>a[i];
        printf("Case %d: %d\n",++kase,solve()-1);
    }
    return 0;
}
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int a[10],n,maxd;
int h()
{
    int cnt=0;
    for(int i=0;i<n-1;i++)
        if(a[i]+1!=a[i+1])cnt++;
    if(a[n-1]!=n) cnt++;
    return cnt;
}

bool dfs(int d)
{
    int cnt=h();
    if(d*3+cnt>maxd*3) return false;
    if(!cnt) return true;
    int b[10],c[10];
    memcpy(b,a,sizeof(a));
    for(int i=0;i<n;i++)
    {
        for(int j=i;j<n;j++)
        {
            int cnt1=j-i+1,cnt2=n-cnt1;
            memcpy(c,b,sizeof(int)*i);
            memcpy(c+i,b+j+1,sizeof(int)*(n-j));
            for(int k=0;k<=cnt2;k++)
            {
                if(i==k) continue;
                memcpy(a,c,sizeof(int)*k);
                memcpy(a+k,b+i,sizeof(int)*cnt1);
                memcpy(a+k+cnt1,c+k,sizeof(int)*(n-cnt1-k));
                if(dfs(d+1)) return true;
            }
        }
    }
    memcpy(a,b,sizeof(a));
    return false;
}

int main()
{
    int kase=0;
    while(cin>>n&&n)
    {
        for(int i=0;i<n;i++) cin>>a[i];
        for(maxd=0;maxd<9;maxd++)
            if(dfs(0)) break;
        printf("Case %d: %d\n",++kase,maxd);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值