1. 程式人生 > >P1020 導彈攔截 /// DP Dilworth定理 LIS優化

P1020 導彈攔截 /// DP Dilworth定理 LIS優化

pro closed can pla break close 下標 return clu

題目大意:

https://www.luogu.org/problemnew/show/P1020

Dliworth有兩個互相對偶的定理:
U的鏈劃分使用的最少集合數,等於它的最大反鏈長度。(1)
U的反鏈劃分使用的最少集合數,等於它的最大鏈長度。(2)

更詳細的講解

技術分享圖片
#include <bits/stdc++.h>
using namespace std;
int a[100005];
int dp1[100005],dp2[100005];
int f1[100005],f2[100005];
/// 將 對應長度的最後一位的下標 存入f1[] f2[]中
/*  即若 2 2 4 3 對應下標為 0 1 2 3
    則長度為 1 2 3 時
    f[]對應為 f[1]   f[2]   f[3] 
                0      1      3  
                2      2 2    2 2 3
*/ int main() { int k=0; while(~scanf("%d",&a[++k])) ; memset(f1,0,sizeof(f1)); memset(f2,0,sizeof(f2)); int t1=0,t2=0; for(int i=1;i<k;i++) { dp1[i]=dp2[i]=1; for(int j=t1;j>0;j--) if(a[f1[j]]>=a[i]) { dp1[i]=j+1; break; } t1
=max(t1,dp1[i]); if(!f1[dp1[i]]) f1[dp1[i]]=i; else if(a[f1[dp1[i]]]<a[i]) f1[dp1[i]]=i; for(int j=t2;j>0;j--) if(a[f2[j]]<a[i]) { dp2[i]=j+1; break; } t2=max(t2,dp2[i]); if(!f2[dp2[i]]) f2[dp2[i]]=i; else
if(a[f2[dp2[i]]]>a[i]) f2[dp2[i]]=i; } printf("%d\n%d\n",t1,t2); return 0; }
View Code

P1020 導彈攔截 /// DP Dilworth定理 LIS優化