UVa11212

/*
迭代加深搜索经典问题,
迭代加深搜索的核心思想是通过不停加深搜索深度来控制解答树的深度和宽度,
对于这一类题目,如果使用DFS,则会因为第一个可行解的深度太大而导致爆栈,
因此搜索的对象是深度,通过控制深度,及时停止过深的搜索。
2.也是搜索问题的共性,就是要有剪枝,
寻找剪枝的方向是根据当前状态和剩下的可行步来计算最好情况下能否获得可行解,如果不行,那么就需要剪枝
3.这中间最主要的剪枝手段就是计算有多少逆序后继数,因为每一次移动一个数字最多使得逆序后继数减三,
因此如果逆序后继数h>3(maxd-d),就说明当前路径下,没有可行解,应剪枝。
*/
#include <iostream>
#include<cstdio>
#include<string>
#include<map>
#include<vector>
#include<sstream>
#include<string.h>
#include<algorithm>
#include<unordered_set>
#include<unordered_map>
#include<utility>
#include<cmath>
#include<time.h>
using namespace std;
int geth(vector<int>&nums){
    int cnt=0;
    for(int i=1;i<nums.size();++i){
        if(nums[i-1]+1!=nums[i])++cnt;
    }
    return cnt;
}
bool dfs(int d,vector<int>&nums,int maxd){
    int i=0,cnt=geth(nums);
    if(cnt==0)return true;
    if(cnt>3*(maxd-d))return false;
    for(i=0;i<nums.size();){
        int j=i+1;
        while(j<nums.size()&&nums[j-1]+1==nums[j])++j;
        for(;j<=nums.size();++j){
            vector<int>tmp=nums,in(nums.begin()+i,nums.begin()+j);
            tmp.erase(tmp.begin()+i,tmp.begin()+j);
            vector<int>lhs=tmp,rhs=tmp;
            auto lp=find(lhs.begin(),lhs.end(),in.front()-1);
            auto rp=find(rhs.begin(),rhs.end(),in.back()+1);
            lhs.insert(lp==lhs.end()?lp:next(lp),in.begin(),in.end());
            rhs.insert(rp,in.begin(),in.end());
            if(dfs(d+1,lhs,maxd)||dfs(d+1,rhs,maxd))return true;
        }
        ++i;
        while(i<nums.size()&&nums[i-1]+1==nums[i])++i;
    }
    return false;
}
int main()
{
    int N,kase=0;
    while(scanf("%d",&N)!=EOF&&N){
        vector<int>nums(N+1,0);
        for(int i=1;i<=N;++i)scanf("%d",&(nums[i]));
        for(int maxd=0;;++maxd){
            if(dfs(0,nums,maxd)){
                printf("Case %d: %d\n",++kase,maxd);
                break;
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/shihongliang1993/article/details/75003517
今日推荐