第一行——咕咕咕。
第二行——我現在才發現我竟然欠了這麼多算法不會(果然講完了不做題就會忘得一乾二淨(自學ing
最長上升子序列:序列不一定唯一,但長度是唯一的
1.我的理解:用dp數組存到第i個數時的最優解,最大即爲最終最優。畢竟dp就是從上一階段的最優解推到先階段最優解。就是以第i個數結尾的最長上升子序列是前i-1個數的最長子序列跟第i個數比較判斷即可。
2.其實如果只讓求最長長度是很簡單的,分暴力+模擬棧(二分兩種,時間複雜度是O(n^2)和O(nlogn)(應該是的(不過模擬棧沒法記錄路徑
3.然而重點是如何記錄路徑(好的我不會
本代碼以SDNU1040爲例
1.偷窺ryc師哥博客後,可得思路
2.攔截系統與上升子序列有關
3.每有一個上升序列的元素,就需要有額外的攔截系統進行攔截
4.若全爲上升序列,則序列有幾個即需要幾個攔截系統
5.其他元素另討論
6.到這裏需要先求出最長上升子序列
7.在序列裏,最長上升子序列之外,分別有前面的大於上升序列首元素,後面的小於上升序列的末尾元素,中間的逆序的元素
8.這些元素,一定可以與上升序列的某個元素組成下降序列,被同一系統攔截
9.一定是上升子序列,因爲非下降子序列(即包含相同元素),因爲相同的可以算一個元素被一個系統攔截。
10.綜上,只需找出最長子序列的長度-1即爲額外所需的導彈攔截系統的個數
//但其實我原本的思路是一次次找最長非上升子序列,標記訪問後再剩下的元素裏找,直至沒有不被訪問過的元素(畢竟oj上數據只有20,不會超過20*20*20)
//我找個時間試試可不可以實現
//就是因爲我沒寫出實現來纔去偷窺了別人的博客
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
int a[25];
int tot = 0;
int ans = 1;
int res = 1;
int dp[25];
while(~scanf("%d",&a[tot]))
{
tot++;
if(getchar()=='\n')
break;
}
for(int i = 0; i < tot; ++i)
{
dp[i] = 1;//截止到第i個數,最長子序列的長度(初始爲1,只有a[i]
for(int j = 0; j < i; ++j)
{
if(a[j]>=a[i]&&dp[i]<dp[j]+1)
{
dp[i] = dp[j]+1;
}
}
res = max(res,dp[i]);
}
for(int i = 0; i < tot; ++i)
{
dp[i] = 1;
for(int j = 0; j < i; ++j)
{
if(a[j]<a[i]&&dp[i]<dp[j]+1)
{
dp[i] = dp[j]+1;
}
}
ans = max(ans,dp[i]);
}
printf("%d,%d\n",res,ans-1);
return 0;
}
附上SDNU其他lis