HDU 1257 最少攔截系統 LIS
怎麼辦呢?多搞幾套系統唄!你說說倒蠻容易,成本呢?成本是個大問題啊.所以俺就到這裡來求救了,請幫助計算一下最少需要多少套攔截系統.
求最長(嚴格)上升序列(Longest Increasing Subsequence)。這樣的長度才是 最少需要的 套數,因為這個序列中的任何兩個導彈都不能共用一個攔截系統 ,而且其餘的導彈 都能和這個最長序列中的某個導彈分為同一組。
證明:對於數列中的一個最長(嚴格)上升序列,長度為k,其餘任何數都可以分在這個最長序列中,構成k組單調減序列:
例如 a1 a2 a3 a4 a5 a6 a7 a8 a9
已經求得 a3 a5 a6 a8 為最長嚴格上升子序列(LSIS),且組成4個組。
對於a9
a9 <= a8 ,否則a9屬於這個LSIS;所以,a9可以和a8分一組。
對於a7
若a7
<= a6, 則a7可以和a6分一組;
若a7 > a6,
a. 如果a7 >= a8,則a7可以和a8分一組;
b. 如果a7 < a8, 則 a6 a7 a8 可替代a6 a8,構成LSIS,矛盾。
對於a4,同a7
對於a2,a2 >= a3,否則與LSIS矛盾。所以,a2與a3可分為一組。
對於a1,
若a1 >=
a2 可與a3同組
若a1 < a2,
a.如果a1 >= a3,可以與a3分在一組
b.如果a1 < a3, 則 a1 a3 可代替a3,與LSIS,矛盾。
同理可證任意n,k。
#include<stdio.h>
#define N 30001
int ary[N], dp[N];
int LIS(int *ary, int n)
{
int i, j, m;
dp[1] = 1;
for(i = 2; i <= n; i++)
{
m = 0;
for(j = 1; j < i; j++)
{
if(ary[i] > ary[j] && dp[j] > m)
{
m = dp[j];
}
}
dp[i] = m + 1;
}
m = 0;
for(i = 1; i <= n; i++)
{
if(dp[i] > m)
m = dp[i];
}
return m;
}
int main()
{
int n, i, j, m;
while(scanf("%d", &n) != EOF )
{
for(i = 1; i <= n; i++)
{
scanf("%d", ary + i);
}
printf("%d\n", LIS(ary, n));
}
}
參考: