蓝桥杯 试题 算法训练 Three Swaps

试题 算法训练 Three Swaps

提交此题   评测记录  

资源限制

内存限制:256.0MB   C/C++时间限制:1.0s   Java时间限制:3.0s   Python时间限制:5.0s

问题描述

  饲养员Xenia有n(n>1)只站成一排的马。每只马都有它自己的独一无二的号码。最开始的时候,从左数第i只马编号为i,也就是说,马的号码序列是下面这样(从左到右):1,2,3,……,n
  Xenia在演出之前训练这些马。在练习期间,她会给马命令。每个命令是一对数l,r(1<=l<r<=n)。命令l,r意思是从左数第l个位置到第r个位置上的马要被重新排列。站在l,r位置上的马交换位置;l+1,r-1位置上的马交换位置;以此类推。也就是说,[l,r]位置内的马反向排列
  例如,如果Xenia命令l=2,r=5并且命令之前马的编号序列为(2,1,3,4,5,6),那么命令之后序列就会是(2,5,4,3,1,6)。
  我们知道在训练时,Xenia最多最多给出三个命令。现在你已经知道了最后马的编号序列,请给出训练时Xenia的命令是什么。注意你不需要使得命令数最小,只需要找到一个在三次命令以内的正确的方案。

输入格式

  第一行包括一个n表示马的数量。第二行包含n个不同的数a1,a2,……,an(1<=ai<=an),ai表示训练完成后从左数第i只马的编号。

输出格式

  第一行包含一个整数k表示Xenia训练时给出的命令数。接下来k行每行输出两个数,第i+1行输出li和ri(1<=li<ri<=n)——Xenia训练时给出的命令。 保证至少出现一个方案。如果出现多组方案,输出任意一组即可。

样例输入

6
2 1 4 3 6 5

样例输出

3
1 2
3 4
5 6

数据规模和约定

  1<n<=1000

        这道题虽然出现在蓝桥杯练习集里,实际上这是国外的一道题,这带来一个问题,这道题每个实例的输出实际上是不唯一的,但是蓝桥杯练习网站在检查时实际上是按照固定答案来判定的所以可能你的代码不能通过!但是可以通过下载输入输出的实例来自行判断自己的代码是否正确,本代码采用dfs,经手动检验是可以解决问题的!但因为递归深度问题一些实例无法计算。

### 问题背景
给定一个长度为`n`的整数序列,目标是通过最多三次操作将其变为升序排列。每次操作可以选择序列中的一个连续子序列并将其翻转。

### 代码逻辑详解

1. **升序检查**:
   - 程序检查序列是否已经是升序排列。

2. **关键位置的确定**:
   - 关键位置是可能需要进行翻转操作的位置。程序遍历序列以查找这些位置,主要是寻找序列中的不连续点,包括:
     - 不满足`a[i] - a[i-1] != a[i+1] - a[i]`的点,表示该位置的数值变化与周围不一致。
     - 与左邻居的差的绝对值不为1的点,表示可能是升序排序中断的地方。
   - 这些关键位置以及序列的起点和终点被存入`pos`向量中。

3. **尝试翻转操作**:
   - 程序尝试通过最多三次翻转操作将序列变为升序。这一过程分为多层尝试。

4. **第一层尝试**:
   - 从`pos`向量中选取两个不同的位置作为一次翻转的起始和终止位置。对子序列进行翻转后,检查整个序列是否已成为升序。如果是,输出该操作并结束。

5. **第二层尝试**:
   - 如果第一次翻转无法解决问题,程序将基于第一次翻转后的序列,再次寻找可能的关键位置,尝试第二次翻转。这一步骤类似于第一层尝试,但是基于已经进行了一次操作的序列。

6. **第三层尝试**:
   - 如果两次翻转仍未能解决问题,程序将尝试第三次翻转。这一次,除了检查序列是否已变为升序外,还会检查翻转的片段是否符合特定的对称性条件。这是因为进行三次操作后,除了全局升序外,还可能需要翻转一个特定的子序列以满足题目要求。

8. **输出结果**:
   - 如果通过上述操作成功将序列变为升序,程序将输出进行的操作数和具体操作(翻转的起始和终止位置)。操作数可以是1到3,根据实际进行的操作次数确定。

通过这种逐步筛选和尝试的方法,程序试图找到一种通过最多三次翻转操作将给定序列变为升序的方案,如果找到了有效的操作序列,就按照要求输出操作细节。

import sys
import copy
sys.setrecursionlimit(1000000000)
n = int(input())
nums = list(map(int, input().split()))
nums_copy = sorted(nums)
stack = []


def find(list1):
    node =[]
    for i in range(len(list1)):
        if i == 0 :
            if list1[i] != 1:
                node.append(i)
                continue
            else:
                continue
        if i == len(list1) - 1:
            if list1[len(list1)-1] != n:
                node.append(i)
                continue
            else:
                continue
        if list1[i-1] - list1[i] != list1[i] - list1[i+1]:
            node.append(i)
    return node


def check(list1):
    if list1 == nums_copy:
        print(len(stack))
        for i in stack:
            print(i[0]+1, i[1]+1)
        sys.exit()
        return True
    else:
        return False


def dfs(t, list1):
    if check(list1):
        return
    elif t >= 3:
        return
    else:
        curnode = find(list1)

        for i in range(len(curnode)-1):
            list2 = copy.deepcopy(list1)
            list2[curnode[i]:curnode[i+1]+1] = sorted(list2[curnode[i]:curnode[i+1]+1])
            stack.append((curnode[i],curnode[i+1]))
            dfs(t+1, list2)
            stack.pop()
dfs(0,nums)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ALBERT JERRY STERLING

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值