13 最大等差数列子集
描述
一个等差数列是指以增序排列后,相邻的两个数后一个与前一个数之差值恒定。规定一个等差数列中的数不应少于3个。任给 n ( 2 < n < 5000)个正整数,请判断可否从中选择子集构成等差数列。若能,则选出满足条件的最大子集合(即,元素个数最多),并按从小到大输出子集中的元素,逗号间隔。若有多个子集同时满足最大,则取差值最大的子集;若同时有多个子集满足集合大小最大,且差值也相等,则取起始元素最大的子集。如果没有满足条件的子集合,则输出 NO.
关于输入
第1行,n,表示整数个数;
第2行,n 个正整数,空格间隔;
关于输出
按增序输出最长等差数列子集,逗号间隔。
例子输入
10
20 14 6 15 22 7 23 8 18 25
例子输出
7,15,23
分析
显而易见的,我们首先要对这个序列排序。在这里我们需要对进行dp,递推公式
本题略有特殊的地方在于,之前的程序里,我们对什么dp,就在循环体里面对这两个东西进行遍历,而在这里我们进行一些优化,不再对 进行遍历,而是对之前的所有位置进行遍历,对于每一个得到一个进行dp
代码实现
#include<iostream>
#include<algorithm>
int dp[5000][5000] = { 0 };//dp[结尾元素][数列公差]
using namespace std;
int main()
{
int n;
int arr[5000] = { 0 };
cin >> n;
for (int i = 0; i < n; ++i)
cin >> arr[i];
sort(arr, arr + n);//排序
int dist = arr[n - 1] - arr[0];//最大公差
for (int i = 0; i < n; ++i)
for (int j = 0; j <= dist; ++j)
dp[i][j] = 1;//初始化:单个元素的长度为1
int max_len = 0, max_k = 0, max_e = 0;
for (int i = 0; i < n; ++i)//对以arr[i]结尾的某个等差数列
{
for (int j = 0; j < i; ++j)//在i之前的,以arr[j]结尾的某个等差数列
{
int diff = arr[i] - arr[j];//这个等差数列的公差是diff
dp[i][diff] = dp[j][diff] + 1;//其实还需要一个比较最大值的步骤,但是在这里,我们显然有在同一个公差下,数列的长度有 后面的>=前面的,故而直接赋值即可
if (max_len < dp[i][diff])//数列长度最优先,强制更新公差、末项
{
max_len = dp[i][diff];
max_k = diff;
max_e = arr[i];
}
else if (max_len == dp[i][diff])//数列长度相等,如果公差比现在的公差小,强制更行末项
{
if (max_k < diff)
max_k = diff, max_e = arr[i];
else if (max_k == diff)//数列长度、公差都相等,选择性更新末项
max_e = max_e > arr[i] ? max_e : arr[i];
}
}
}
//以下是输出结果,略
来源:CSDN
作者:Chen#123
链接:https://blog.csdn.net/weixin_44351043/article/details/104442793