这个题一开始没什么思路,只是听以前A过的大佬说这题是什么最长上升子序列最长不上升子序列巴拉巴拉什么玩意儿的ios
那时候菜听不懂 虽然如今也菜 而后我去看了洛谷网课发的ppt上面讲的最长上升子序列(跟最长不上升子序列是差很少的啦)数组
其实也没太看懂。。(qwq了炸菜的真我spa
可是后来想一想实际上是一个很简单的思路:当前的数的最长不上升子序列=以前的每个大于它的数中最长的不上升子序列+1 |或者| 当前的数的最长不上升子序列=当前的数的不上升子序列code
(取最大的那个就能够blog
这个思路就像一堆嫌贫爱富的小同窗找朋友同样:不少个小同窗排成一排,他们都喜欢跟最有钱的人成为朋友,找到了朋友那个朋友的钱财就属于他们两个的了(固然他本身的钱不属于那个朋友),而且若是之后有人选择他作朋友,那么他朋友的钱也是他另外一个朋友的钱(他的朋友骂骂咧咧的走了),并且那个朋友年龄还必须比他大(大孩子会照顾人欸),否则再有钱他们俩也不会成为朋友的(毕竟小孩子比较小气,不愿跟朋友分享本身的软妹币)。但是他们只能知道本身以前的孩子的钱数以及岁数,因此他们要开始一个一个比较看看哪个最适合当他的朋友。小花今年14岁了,如今他该选朋友了。他首先来到靠着他最近的一个小朋友问:“你多少岁啊?” 那个小朋友说:“我今年12岁了!”小花想:这个小朋友比我小,他确定不会把他的软妹币分给我!那我就继续往前走吧。小花来到他前面第二个小朋友(就先叫他小明吧)面前问:“你今年多少岁哇?”小明说:“我今年18岁了!”小花想:这个小朋友比我大,大孩子确定大方,那我就跟他作朋友吧!因而他们两个成为了要好的朋友。但是小花又想了:万一前面还有小朋友比我大,并且比小明富有可怎么办啊??那我先让小明把他的软妹币分给我,我再往前找找看,若是有比小明更富有的就抛弃小明把(话说你怎么这么不要脸啊喂!!!),因而小花继续往前走......最终小花遇到了一个年龄跟他通常大并且极其富有的小朋友,因而他们幸福快乐的生活在了一块儿(bushi)......因而小花拿了这个小朋友的钱就走了(太不要脸了真的是)。io
提及来这么麻烦其实就是一行代码啦:t[i]=max(t[i],t[j]+1);(j<i)class
而后就是这么简单,这是代码,最后输出maxx就ok啦(a数组是存数的):stream
for(int i=0;i<n;i++){//遍历每个数 for(int j=i-1;j>=0;j--){//遍历每个小于i的数 if(a[j]>=a[i]){//若是当前的数符合条件(即找到了一个大于等于a[i]的数 t[i]=max(t[i],t[j]+1);//动态转移方程,刚才解释过了 } } } for(int i=0;i<n;i++){//遍历t数组 maxx=max(maxx,t[i]);//取最长的不上升子序列 t[i]=1;//一会还要用,因此要初始化 }
关于初始化我要说明一下,为何要让t数组的最长不上升子序列的值都初始化为1呢?由于每个数均可以看做为一个开始的数。不是每次都会让t[i]的值更新吗?t[j]+1确定会大于等于t[i]啊,为何还要费这么多事?由于咱们还加了一个特判条件a[j]>=a[i],若是a[j]<a[i]这一条就不会被执行到了,咱们下次若是要用到这个数,他的最长上升子序列就会少个1。固然你在if后面加一个else而后让t[i]=1也是能够的,但是那样就很麻烦了。看你心情咯百度
而后咱们再看第二个输出,理解起来可能有点麻烦,但其实就是让你找到最少而且能够覆盖整个数列的最长不上升子序列。遍历
听起来好麻烦哦。。。并且毫无思路
因而我查啊查啊终于知道了一个很神奇的东西:Dilworth定理
他是一个可让咱们A题的关键,因此我满怀期待取百度了一下这个陌生的词:
行吧,是我卑微了(看不懂就很好
可是为了让你们理解这个定理,我找到了一个更通俗易懂的说法:
是否是感受清楚多了??
代码实现也不难,直接把上面的代码复制粘贴过来把>=改为<就ok啦
不过这里有一个咱们须要咬文嚼字的地方:最长不上升子序列&最长上升子序列
最长不上升子序列:只要不上升,降低或者相等也能够
最长上升子序列:必须上升
这就是为何咱们在改的时候不改为<=
最终代码放一下:
#include<iostream> #include<cstdio> using namespace std; int n,a[100010],t[100010],ans=0,maxx=0,minn=0; int main(){ while(scanf("%d",&a[n])!=-1){//无限输入,不会的能够复制一下啦(其实我也是在小姐妹那里求来的qwq) t[n]=1;//千万不要忘了初始化!!! n++;//看这些数一共有多少个 } t[0]=1; for(int i=0;i<n;i++){ for(int j=i-1;j>=0;j--){ if(a[j]>=a[i]){ t[i]=max(t[i],t[j]+1);//动态转移方程 } } } for(int i=0;i<n;i++){ maxx=max(maxx,t[i]);//求最长不上升子序列 t[i]=1;//再次初始化 } for(int i=0;i<n;i++){ for(int j=i-1;j>=0;j--){ if(a[j]<a[i]){ t[i]=max(t[i],t[j]+1);//依然是动态转移方程 } } } for(int i=0;i<n;i++){ minn=max(minn,t[i]);//求最长上升子序列 } printf("%d\n%d\n",maxx,minn);//输出 return 0; }