P1020 導彈攔截

注:本蒟蒻只得了100分,那些想經過看這篇文章獲得200分的同窗能夠溜了喔

這個題一開始沒什麼思路,只是聽以前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;
}

再次強調:我只得了100,若是你想看個人這篇文章得200分是不可能的

以上僅是我的對於這道題的所有思路與想法,若是有什麼不對的地方,還請各位大佬及時向我糾正。

相關文章
相關標籤/搜索