如何用O(nlogn)的的速度求解最长上升(下降)子序列
2010-07-12 11:16
337 查看
打导弹解题有感
求一个序列的最长上升子序列,可以用贪心的思想来做。
例:389 207 155 300 299 170 158 65
要求它的最长递减子序列,具体步骤如下:
389
389 207
389 207 155
389 300 155 //207被300替换了,207是三个数中刚好小于300的数,207能接的后序列,300照样能接,而且有更大的空间可以接
389 300 299 //此次用299替换155,一样是因为有更大的空间可用,在这里就体现了用300来替换207的正确性
389 300 299 170
389 300 299 170 158
389 300 299 170 158 65
这样就得到了一个最长递减子序列,而且更有可能接更多的数
由于在这个贪心的过程中,辅助数组是有序的,就可以用二分查找来优化,最终将时间优化到O(nlogn)
对于打导弹这道题,求最少的导弹拦截系统的个数,实践最终证明,他等价于求最长上升子序列,类似于对偶优化问题,看它的贪心过程就可知道,它是如何等价于求最长上升子序列的,过程如下:
389
207
155
155 300
155 299
155 170
155 158
56 158 // 找到刚大于56的,然后替换掉,是最优的选择
代码如下:
代码
补充:这种方法只能求得长度,如果要输出这个序列,还需要另外的算法。sgu199还是不能做!!!!
求一个序列的最长上升子序列,可以用贪心的思想来做。
例:389 207 155 300 299 170 158 65
要求它的最长递减子序列,具体步骤如下:
389
389 207
389 207 155
389 300 155 //207被300替换了,207是三个数中刚好小于300的数,207能接的后序列,300照样能接,而且有更大的空间可以接
389 300 299 //此次用299替换155,一样是因为有更大的空间可用,在这里就体现了用300来替换207的正确性
389 300 299 170
389 300 299 170 158
389 300 299 170 158 65
这样就得到了一个最长递减子序列,而且更有可能接更多的数
由于在这个贪心的过程中,辅助数组是有序的,就可以用二分查找来优化,最终将时间优化到O(nlogn)
对于打导弹这道题,求最少的导弹拦截系统的个数,实践最终证明,他等价于求最长上升子序列,类似于对偶优化问题,看它的贪心过程就可知道,它是如何等价于求最长上升子序列的,过程如下:
389
207
155
155 300
155 299
155 170
155 158
56 158 // 找到刚大于56的,然后替换掉,是最优的选择
代码如下:
代码
#include<stdio.h> #define NN 10004 int tmp[NN], high[NN]; int index; int find1(int t){ int low = 0; int hig = index - 1; int ans = -1; do { int mid = (low + hig) / 2; if (tmp[mid] < high[t]){ ans = mid; hig = mid - 1; }else{ low = mid + 1; } }while (low <= hig); return ans; } int find2(int t){ int low = 0; int hig = index - 1; int ans = -1; do { int mid = (low + hig) / 2; if (tmp[mid] >= high[t]){ ans = mid; hig = mid - 1; }else{ low = mid + 1; } }while (low <= hig); return ans; } int main() { int i, n, t; while (scanf("%d", &n)!= EOF){ if (n == 0) break; for (i = 0; i < n; i++){ scanf("%d", &high[i]); } tmp[0] = high[0]; index = 1; for (i = 1; i < n; i++){ t = find1(i); if (t == -1){ tmp[index++] = high[i]; }else tmp[t] = high[i]; } printf("%d\n", index); tmp[0] = high[0]; index = 1; for (i = 1; i < n; i++){ t = find2(i); if (t == -1){ tmp[index++] = high[i]; }else tmp[t] = high[i]; } printf("%d\n", index); } return 0; }
补充:这种方法只能求得长度,如果要输出这个序列,还需要另外的算法。sgu199还是不能做!!!!
相关文章推荐
- 最长上升(下降)子序列 O(nlogn)
- 最长非上升/非下降子序列(O(nlogn)非连续)
- 最长上升子序列、最长下降子序列的DP算法由O(n^2)到O(nlogn)算法
- 最长上升子序列、最长下降子序列的DP算法由O(n^2)到O(nlogn)算法实现及其优化
- 蓝桥杯算法训练拦截导弹【最长上升子序列 & 最长非下降子序列nlogn 和 n^2】
- hdu 5747 最长上升子序列 (nlogn)
- 算法:最长上升下降子序列
- hdu 5748(求解最长上升子序列的两种O(nlogn)姿势)
- HDU 5748 最长上升子序列的长度nlogn(固定尾部)
- UVa 10534 - Wavio Sequence DP+最长上升子序列(严格上升)+二分查找(nlogn)
- 最长上升子序列(LIS)长度的O(nlogn)算法
- <序列DP>O(nlogn)的最长上升子序列
- 题目1533:最长上升子序列 (nlogn | 树状数组)
- 最长不下降子序列的O(n^2)算法和O(nlogn)算法
- HDU 1025 DP+二分求解最长上升序列
- 求最长上升/下降子序列【O(nlgn)】
- nlogn求最长上升子序列长度(二分 找序列)
- HDU 5748 Bellovin(最长上升子序列[nlogn])
- BZOJ1046(HAOI2007)[上升序列]--最长下降子序列预处理
- hdu1025 最长上升子序列 O(nlogn)优化版