• UVA


    题目:

    给出n(1<n<10)个数字组成的序列,每次操作可以选取一段连续的区间将这个区间之中的数字放到其他任意位置。问最少经过多少次操作可将序列变为1,2,3……n。

    思路:

    利用IDA*来求解这个题目,首先每步操作最多可以减少3个位置错误的数字如下图(假设操作之后a、b、c都位于正确的位置)

    则启发函数可以为3*cur+h > maxd*3,其中cur是枚举到当前的操作次数,h是序列中位置不对的数字个数,maxd是枚举到的答案。

    可以用两重循环枚举选取的区间,然后枚举将其放到的位置,dfs知道序列符合题意。

    代码:

    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define MAX 1000000009
    #define FRE() freopen("in.txt","r",stdin)
    #define FRO() freopen("out.txt","w",stdout)
    using namespace std;
    typedef long long ll;
    const int maxn = 10;
    int n;
    
    bool isSrot(int* buf){//判断是不是序列符合题意
        for(int i=0; i<n-1; i++){
            if(buf[i]>=buf[i+1])
                return false;
        }
        return true;
    }
    
    int ErrorNum(int* buf){//输出位置不对的数字个数
        int cnt = 0;
        for(int i=0; i<n-1; i++){
            if(buf[i]+1!=buf[i+1])
                cnt++;
        }
        return cnt;
    }
    
    void numSwap(int* buf,int* original,int s,int t,int pos){//将区间放到指定的位置
        int idx=0;
        for(; idx<pos; idx++){
            buf[idx] = original[idx];
        }
    
        for(int i=s; i<t; i++){//将操作的区间放入buf数组
            buf[idx++] = original[i];
        }
        for(int i=pos; i<n; i++){//将剩余部分补全
            if(i<s || i>=t){
                buf[idx++] = original[i];
            }
        }
    }
    
    bool dfs(int cur,int maxd,int* a){
        if(3*cur+ErrorNum(a)>3*maxd) return false;
        if(isSrot(a)) return true;
    
        int temp[10];
        for(int s=0; s<n; s++){//这两重循环是用来枚举剪切的区间的长度
            for(int t=s+1; t<=n; t++){
                for(int pos=0; pos<s; pos++){//枚举区间要放入的位置,只要放到s之前就可以枚举所有的情况
                                            //别的地方也不符合实际情况啊,做的时候写成了pos<n,结果一直T
                    numSwap(temp, a, s, t, pos);
                        if(dfs(cur+1, maxd, temp))
                            return true;
                }
            }
        }
        return false;
    }
    
    int main(){
        //FRE();
        int kase = 0,a[10];
        while(scanf("%d",&n) && n){
            for(int i=0; i<n; i++){
                scanf("%d",&a[i]);
            }
    
            for(int i=0; i<=n; i++){
                if(dfs(0,i,a)){
                    printf("Case %d: %d
    ",++kase,i);
                    break;
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    2、函数
    二者取其一(初遇)_网络流
    P1879 [USACO06NOV]玉米田Corn Fields
    P2831 愤怒的小鸟
    P2296 寻找道路
    序(不知道是什么时候的模拟题)
    P2243 电路维修
    P1273 有线电视网
    P2613 【模板】有理数取余
    P1373 小a和uim之大逃离
  • 原文地址:https://www.cnblogs.com/sykline/p/10321539.html
Copyright © 2020-2023  润新知