生活随笔
收集整理的這篇文章主要介紹了
最长公共上升子序列(LCIS)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:
求最長公共上升子序列
題解:
最長公共上升子序列 = 最長公共子序列(LCS)與最長上升子序列(LIS)
LCS核心代碼:
for
(int i
=1
;i
<=n
;i++
){for
(int j
=1
;j
<=m
;j++
){if
(a
[i
]==b
[j
])dp
[i
][j
]=max
(dp
[i
][j
],dp
[i-1
][j-1
]+1
);else dp
[i
][j
]=max
(dp
[i-1
][j
],dp
[i
][j-1
]);}}
LIS核心代碼:
for
(int i
=1
;i
<=n
;i++
){dp
[i
]=1
;for
(int j
=1
;j
<i
;j++
){if
(a
[j
]<a
[i
])dp
[i
]=max
(dp
[i
],dp
[j
]+1
);}mx
=max
(mx,dp
[i
]);}
最長公共上升子序列的代碼就是在最長公共子序列上找一遍最長上升子序列即可。也就是在判斷a[i] = = b[j]的前提下,再求出上升序列
f[i][j]代表所有a[1 ~ i]和b[1 ~ j]中以b[j]結尾的公共上升子序列的集合;
f[i][j]的值等于該集合的子序列中長度的最大值;
復雜度O(n3)
代碼:
for (int i
= 1
; i
<= n
; i ++
)
{for (int j
= 1
; j
<= n
; j ++
){f
[i
][j
] = f
[i - 1
][j
];if (a
[i
] == b
[j
]){int maxv
= 1
;for (int k
= 1
; k
< j
; k ++
)if (a
[i
] > b
[k
])maxv
= max
(maxv, f
[i - 1
][k
] + 1
);f
[i
][j
] = max
(f
[i
][j
], maxv
);}}
}
我們仔細看看代碼,第三層for循環是用來求之前的,小于a[i]的最長公共上升子序列+1長度,實際上我們需要知道的只有之前的最長公共上升子序列的長度,這樣一來我們可以用一個變量val來存放 F[ i-1 ][ k ] 中的最大值,從而就可以省略第三層循環
for (int i
= 1
; i
<= n
; i ++
){int maxv
= 1
;for (int j
= 1
; j
<= n
; j ++
){f
[i
][j
] = f
[i - 1
][j
];if (a
[i
] == b
[j
]) f
[i
][j
] = max
(f
[i
][j
], maxv
);if (a
[i
] > b
[j
]) maxv
= max
(maxv, f
[i - 1
][j
] + 1
);}}
我們還可以將維度縮到一維
可知f[i][j]都是由f[i-1][j]得來的
我們用f[i]表示a序列前i個元素與b序列的(LCIS)長度,t為最長LCIS的結尾元素位置,新的轉移方程:
f[i] = f[t] +1 (a[i] = b[j])
這樣就降到一維
for
(int i
=1
;i
<=n
;i++
){maxx
=0
;for
(int j
=1
;j
<=n
;j++
){if
(b
[j
]<a
[i
]&&maxx
<f
[j
]) maxx
=f
[j
];if
(b
[j
]==a
[i
]) f
[j
]=maxx+1
;}}
代碼:
二維空間的代碼:
using namespace std
;const int N
= 3010
;int n
;
int a
[N
], b
[N
];
int f
[N
][N
];int main
()
{scanf
("%d",
&n
);for (int i
= 1
; i
<= n
; i ++
) scanf
("%d",
&a
[i
]);for (int i
= 1
; i
<= n
; i ++
) scanf
("%d",
&b
[i
]);for (int i
= 1
; i
<= n
; i ++
){int maxv
= 1
;for (int j
= 1
; j
<= n
; j ++
){f
[i
][j
] = f
[i - 1
][j
];if (a
[i
] == b
[j
]) f
[i
][j
] = max
(f
[i
][j
], maxv
);if (a
[i
] > b
[j
]) maxv
= max
(maxv, f
[i - 1
][j
] + 1
);}}int res
= 0
;for (int i
= 1
; i
<= n
; i ++
) res
= max
(res, f
[n
][i
]);printf
("%d\n", res
);return 0
;
}
一維數組的代碼:
using namespace std
;
inline int read
(){int x
=0,f
=1
; char ch
=getchar
();while
(!isdigit
(ch
)) {if
(ch
=='-')f
=-1
;ch
=getchar
();}while
(isdigit
(ch
)) {x
=x*10+ch-48
;ch
=getchar
();}return x*f
;
}
int n,a
[maxn
],b
[maxn
],f
[maxn
],maxx
;
signed main
(){n
=read
();for
(int i
=1
;i
<=n
;i++
) a
[i
]=read
();for
(int i
=1
;i
<=n
;i++
) b
[i
]=read
();for
(int i
=1
;i
<=n
;i++
){maxx
=0
;for
(int j
=1
;j
<=n
;j++
){if
(b
[j
]<a
[i
]&&maxx
<f
[j
]) maxx
=f
[j
];if
(b
[j
]==a
[i
]) f
[j
]=maxx+1
;}}maxx
=0
;for
(int i
=1
;i
<=n
;i++
) if
(maxx
<f
[i
]) maxx
=f
[i
];printf
("%d",maxx
);return 0
;
}
總結
以上是生活随笔為你收集整理的最长公共上升子序列(LCIS)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。