排书(dfs剪枝)

本文介绍了一种解决将书籍排列至1~n顺序问题的算法,使用深度优先搜索(DFS)结合剪枝策略,目标是最少操作次数。通过模拟操作和递归搜索,确定最少需要的操作次数,当操作次数大于或等于5次时输出提示。

这个题做起来特别无语,发现自己一些正常的模拟操作都需要联系

给定 n 本书,编号为 1∼n。

在初始状态下,书是任意排列的。

在每一次操作中,可以抽取其中连续的一段,再把这段插入到其他某个位置。

我们的目标状态是把书按照 1∼n 的顺序依次排列。

求最少需要多少次操作。

输入格式

第一行包含整数 T,表示共有 T 组测试数据。

每组数据包含两行,第一行为整数 n,表示书的数量。

第二行为 n 个整数,表示 1∼n的一种任意排列。

同行数之间用空格隔开。

输出格式

每组数据输出一个最少操作次数。

如果最少操作次数大于或等于 5 次,则输出 5 or more

每个结果占一行。

数据范围

1≤n≤15

输入样例:

3
6
1 3 4 6 2 5
5
5 4 3 2 1
10
6 8 5 3 4 7 2 9 1 10

输出样例:

2
3
5 or more

代码:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=16;
int q[N];
int g[6][N];
int n;
int f()
{
    int tot=0;//tot用于记住每个数后缀出现错误的数
    for(int i=1;i<=n-1;i++)
        if(q[i]+1!=q[i+1])
        tot++;

    return (tot+2)/3;//因此每次交换只能改变三个后缀(假设每次都能正确改回三个)
}
bool panduan()
{
    for(int i=1;i<=n;i++)
        if(q[i]!=i)
            return false;
    return true;
}
bool dfs(int u,int depth)
{
    if(u+f()>depth)return false;//如果最优情况下,交换的已经次数都大于depth的话,直接返回false
    if(panduan())return true;//找到解后返回
    for(int len=1;len<n;len++)
        for(int qi1=1;qi1+len-1<=n;qi1++)
    {
        int r=qi1+len;
        for(int wai=r;wai<=n;wai++)
        {
            memcpy(g[u],q,sizeof q);
            int i,j;//i用于记住每次对接的起点,j表示每次对接的长度。注意!!!

            //将某个块砍掉在接起来,一定要记住每次对接的末尾
            for(i=qi1,j=r;j<=wai;i++,j++)q[i]=g[u][j];
            for(j=qi1;j<=qi1+len-1;i++,j++)q[i]=g[u][j];
            if(dfs(u+1,depth)){
                    return true;
            }
            memcpy(q,g[u],sizeof g[u]);
        }
    }

    return false;
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i=1;i<=n;i++)
            scanf("%d",&q[i]);
        int depth=0;

        while(depth<=5&&!dfs(0,depth))
                depth++;
        if(depth<5)
            printf("%d\n",depth);
        else
            printf("5 or more");
    }

    return 0;
}
 

请使用c++14 ## 题目背景 ![](https://cdn.luogu.com.cn/upload/image_hosting/e4xpr0c2.png) 图为 Dr. Philippe Garigue 收藏中的古籍架。 图片来源:Taylor Tryburski,CC BY-SA 4.0。 ## 题目描述 在摆放籍的问题上,藏家与室内设计师往往难以达成一致:直立?横放?究竟哪种方式才是“正确”的? 而你,总是对传统见解保持怀疑,于是选择了——两者都要! 你的架呈现出一种别具风格的组合:整齐直立的籍旁,是一摞精心列的水平堆叠籍,看上去宛如文学版的阶梯神庙。整体效果既展示了波西米亚式的自由随性,又带着点可爱的学者式心不在焉,同时又有足够的精致暗示:你确实读过其中的一些。 一本书由其脊高度与厚度来描述。如果它的高度不超过架的高度,则可以直立摆放。 或者,也可以横放,彼此叠加成一摞;出于美观考虑,这个堆叠中籍的脊高度必须按不增顺序列。堆叠中所有籍的总厚度不得超过架高度。 而直立籍的总厚度与堆叠的宽度之和不得超过架的宽度。 样例 1 中的籍可以按照下图摆放: ![](https://cdn.luogu.com.cn/upload/image_hosting/vm62fwym.png) ## 输入格式 输入包含: - 一行,三个整数 $N$, $H$, $W$($2 \le N \le 100$, $130 \le H \le 350$, $300 \le W \le 900$),分别表示要摆放的本数量、架高度(毫米)与架宽度(毫米), - 接下来 $N$ 行,每行两个整数 $h$, $t$($76 \le h \le 483$, $5 \le t \le 60$),表示一本书脊高度与厚度(毫米)。题目保证每本书单独放置时,既可直立也可横放,因此满足 $h \le \max(W, H)$。 ## 输出格式 输出两行。 第一行以单词 `upright` 开头,随后输出所有直立籍的编号。 第二行以单词 `stacked` 开头,随后输出堆叠中籍的编号,从底到顶依次列。 要求至少有一本直立籍,且至少有一本堆叠籍。籍编号为 $1$ 至 $N$。 如果答案不唯一,你可以输出任意一个。若不存在满足条件的摆放方式,则输出 `impossible`。 ## 输入输出样例 #1 ### 输入 #1 ``` 3 250 350 178 32 200 60 297 50 ``` ### 输出 #1 ``` upright 1 stacked 3 2 ``` ## 输入输出样例 #2 ### 输入 #2 ``` 2 300 300 290 60 290 60 ``` ### 输出 #2 ``` impossible ``` ## 说明/提示
11-16
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值