Peter算法小课堂—单调子序列

最长上升子序列

dp解法:

f[i]表示以i结尾的最长上升子序列的长度

按照倒数第二个选谁分类:

我们先扫描i号元素前的每个元素(正向),找出第一个比i号元素小的元素k号。①仍然选i号元素,f[i]。②选k号,f[k]+1

但是,这种解法时间复杂度为O(N^2),一但长度到200,就会扣分,我们这次就讨论O(nlog n)的算法。

不升子序列最小划分数

我们用贪心解决这个问题。定义d[i]为第i条不升子序列的最后一个数,cnt代表有几个子序列

我们先扫描每个数字x[i],再枚举每一个子序列,判断是否能接在某个子序列后,如果不行,则新增一个序列即可。

#include 
#define N 1005
using namespace std;
int n,i,j,d[N],x[N];
int main(){
	cin>>n;
	for(int i=0;i>x[i];
	int cnt=0;
	for(i=0;i=x[i]) break;
		d[j]=x[i];
		if(j==cnt) cnt++;
	}
	cout<

但是这个算法时间复杂度也是O(N^2),我们要进行优化

我相信,聪明的你们一定能想到二分查找

#include 
#define N 1005
#define INF 2e9
using namespace std;
int n,d[N],x[N];
int main(){
	cin>>n;
	for(int i=0;i>x[i];
	fill(d,d+n,INF);
	for(i=0;i

Dilworth反链

Peter算法小课堂—单调子序列_第1张图片

LIS为最长子序列, 那么说明一定能找到LIS个数,从左往右是递增的。那么这些树一定不能放在同一组内,不然与不升矛盾。到目前为止,每个数单独为一组,已经开了LIS组了。说明任何一种满足要求的分组,组数都>=LIS。

所以,回到LIS,代码如下

#include 
#define N 1005
#define INF 2e9
using namespace std;
int n,d[N],x[N];
int main(){
	cin>>n;
	for(int i=0;i>x[i];
	fill(d,d+n,INF);
	for(i=0;i

*若为严格下降子序列最小划分,则把lower_bound变为upper_bound 

综合运用

Peter算法小课堂—单调子序列_第2张图片

Peter算法小课堂—单调子序列_第3张图片 

 希望这些对大家有用,三联必回

你可能感兴趣的:(动态规划,算法,c++,图论)