本文主要是介绍1443 拍照(枚举 + 推公式),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1. 问题描述:
农夫约翰在给他编号为 1…N 的 N 头奶牛排队拍照。约翰一开始计划从左向右数第 i 个位置排编号为 ai 的奶牛,他在一张纸上写下了排列 a1,a2,…,aN。不幸的是,这张纸刚刚被小偷偷走了!幸好约翰仍然有机会恢复他之前写下的排列。在这张纸被偷走之前,奶牛贝茜记录了序列 b1,b2,…,bN−1,对于每一个 1 ≤ i < N 满足 bi = ai + ai+1。基于贝茜的信息,帮助约翰恢复可以产生序列 b 的"字典序最小"的排列 a。排列 x 字典序小于排列 y:如果对于某个 j,对于所有 i < j 均有 xi = yi,且有 xj < yj(换句话说,这两个排列到某个位置之前都相同,在这个位置上 x 小于 y)。保证存在至少一个满足条件的 a。
输入格式
输入的第一行包含一个整数 N。第二行包含 N−1 个空格分隔的整数 b1,b2,…,bN−1。
输出格式
输出一行,包含 N 个空格分隔的整数 a1,a2,…,aN。
数据范围
2 ≤ N ≤ 10 ^ 3
输入样例:
5
4 6 7 6
输出样例:
3 1 5 2 4
样例解释
a 能够产生 b,因为 3+1=4,1+5=6,5+2=7,2+4=6。
来源:https://www.acwing.com/problem/content/1445/
2. 思路分析:
对于这种存在公式的题目我们需要先推导一下,发现一下其中的规律,我们可以写出所有的等式可以发现当bi确定之后实际上是一个n个未知数和n - 1个方程的线性方程组,根据线性方程组的相关知识可以知道方程组存在无穷多解或者无解的情况,而题目中规定了至少存在一组解,所以肯定是有解的。n个未知数n-1个方程所以肯定存在一个自由变量,不妨设a1为自由变量所以当a1的值确定之后,那么a2~an的值也是确定的,所以我们可以枚举a1的所有可能取值,也即枚举1~n,通过下图中的公式递推出a2~an,因为题目中要求a1~an是一个排列所以在递推ai的过程中判断生成的ai是否符合要求,如果当n个元素ai都符合要求那么直接返回结果即可,因为第一次找到的满足要求的一定是字典序最小的。
3. 代码如下:
from typing import Listclass Solution:# 判断当前的a1推导出的其余ai是否是一个排列def check(self, a1: int, n: int, b: List[int]):# st用来标记对应的数字是否已经被使用过了st = [0] * (n + 10)a = [0] * (n + 10)a[1] = a1st[a1] = 1for i in range(2, n + 1):# 推导出其余的aia[i] = b[i - 1] - a[i - 1]# 越界了if a[i] < 0 or a[i] > n: return False# 存在重复if st[a[i]]: return Falsest[a[i]] = 1# 没有重复没有越界且总共有n个元素说明是一个排列输出排列for i in range(1, n + 1):print(a[i], end=" ")return True# 枚举 + 推公式def process(self):n = int(input())# b的前面加上一个0这样下标可以从1开始比较好处理b = [0] + list(map(int, input().split()))for i in range(1, n + 1):if self.check(i, n, b):breakif __name__ == "__main__":Solution().process()
这篇关于1443 拍照(枚举 + 推公式)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!