数列4 动态规划

数列4

题目描述

  虽然蔡书苹长大了,但她还是很喜欢找点游戏自娱自乐。有一天,她在纸上写了一串数字:1,1,2,5,4。接着她擦掉了一个1,结果发现剩下1,2,4都在自己所在的位置上,即1在第1位,2在第2位,4在第4位。她希望擦掉某些数后,剩下的数列中在自己的位置上的数尽量多。她发现这个游戏很好玩,于是开始乐此不疲地玩起来…不过她不能确定最后能有多少个数在自己的位置上,所以找到你,请你帮忙计算一下!

输入格式

第一行为一个数n,表示数列的长度。
接下来一行为n个用空格隔开的正整数,第i行表示数Ai。

输出格式

一行,一个整数,表示擦掉某些数后,最后剩下的数列中最多能有多少个数在自己的位置上,即Ai=i最多能有多少。

输入样例

5
1 1 2 5 4

输出样例

3

解题思路

本题大意:求一个序列删除若干数后,使得剩下的数与自己所在位置相等的个数最多。

通过观察题目,我们可以对 A A A数列中的数进行分类讨论,设 p o s i pos_i posi A i A_i Ai目前所在的位置:

  1. A i > p o s i A_i>pos_i Ai>posi,那么无论怎么删数, A i A_i Ai都不可能到达它原来的位置。
  2. A i = p o s i A_i=pos_i Ai=posi,那么不用删数, A i A_i Ai就在它原来的位置上。
  3. A i &lt; p o s i A_i&lt;pos_i Ai<posi,那么删去若干个数, A i A_i Ai就会在它原来的位置上。

综上所述,我们只需考虑第2,第3种情况,并且发现最后到达自己原来位置的数呈现出单调上升的趋势,因此我们考虑使用动态规划,由此本题正解很明显是线性动态规划

我们设 f [ i ] f[i] f[i]表示以 A i A_i Ai结尾,前面所能组成的最长的答案数列。那么 A i A_i Ai可以作为前面其中一些合法数列的结尾,我们设前面符合第2,第3条件的数为 A k 1 , A k 2 , A k 3 ⋯ A k x A_{k_1},A_{k_2},A_{k_3}\cdots A_{k_x} Ak1,Ak2,Ak3Akx,但是并不是所有数列后面都能接 A i A_i Ai,举个例子:

i i i 1 2 3 4 5 6
A i A_i Ai 5 1 2 4 6 3

在这个数列中 A 2 , A 3 , A 4 A_2,A_3,A_4 A2,A3,A4都是可以回到原来的位置的,如果以 A 4 A_4 A4为某个合法数列的结尾,那么这个合法数列最长为1,就是他自己。因为 A 4 A_4 A4如果接在 A 2 , A 3 A_2,A_3 A2,A3的后面,那么当这两个数回到原来位置后, A 4 A_4 A4就会变成第1种情况,变得不合法。

由此我们知道,如果以 A i A_i Ai为结尾,那么设它可以接在 A k j A_{k_j} Akj后面, A k j A_{k_j} Akj A i A_i Ai满足以下条件:

  1. A k j &lt; A i A_{k_j}&lt;A_i Akj<Ai
  2. p o s i − p o s k j ≥ A i − A k j pos_i-pos_{k_j}\geq A_i-A_{k_j} posiposkjAiAkj

状态转移方程: f [ i ] = m a x ( f [ i ] , f [ k j ] + 1 ) f[i]=max(f[i],f[k_j]+1) f[i]=max(f[i],f[kj]+1)


代码

/*
1.a[i]必须在i或i之后才有可能到达原来的位置
2.若最长数列里有a[i]和a[j]且i<j,那么有a[i]<a[j] 且 a[j]-a[i](数值上的差)<=j-i(位置上的差) 且 a[i]!=a[j] 
*/
#include<iostream>

using namespace std;
int n;
int a[1005],f[1005],ans;
/*
f[i]表示以a[i]结尾所得的最长序列
根据以上条件可得
f[i]=max(f[i],f[k1]+1,f[k2]+1...,f[kn]+1) (kn<i&&a[i]>a[kn]&&a[i]!=a[kn]&&a[i]-a[kn]<=i-kn) 
*/
int main()
{
    
    
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	for(int i=1;i<=n;i++)
		if(a[i]<=i)
		{
    
    
			f[i]=1;
			for(int j=1;j<i;j++)
				if(a[j]<=j&&(i-j>=a[i]-a[j])&&a[i]>a[j])
					f[i]=max(f[i],f[j]+1);
		}
	for(int i=1;i<=n;i++)
		ans=max(f[i],ans);
	cout<<ans;
	return  0;
}

猜你喜欢

转载自blog.csdn.net/bell041030/article/details/89490852
今日推荐