POJ 3670 Eating Together 二分解法O(nlgn)和O(n)算法
来源:互联网 发布:暖风机哪个牌子好 知乎 编辑:程序博客网 时间:2024/05/22 00:19
本题就是一题LIS(最长递增子序列)的问题。本题要求求最长递增子序列和最长递减子序列。
dp的解法是O(n*n),这个应该大家都知道,不过本题应该超时了。
因为有O(nlgn)的解法。
但是由于本题的数据特殊性,故此本题可以利用这个特殊性加速到O(n)的解法,其中的底层思想是counting sort分段的思想。就是如果你不会counting sort的话,就很难想出这种优化的算法了。
O(nlgn)的利用单调队列性质的解法,利用二分加速是有代表性的,无数据特殊的时候也可以使用,故此这里先给出这个算法代码。
看了代码就知道很简单的了,不过这里为了更加高效利用代码,就使用了函数指针,代码十分简洁了,初学者耐心点看,代码应该很好的:
#include <stdio.h>const int MAX_N = 30000;int arr1[MAX_N], arr2[MAX_N];inline int max(int a, int b) { return a > b? a : b; }inline bool larEqu(int a, int b) { return a <= b; }inline bool smaEqu(int a, int b) { return a >= b; }int biSearch(int low, int up, int val, bool (*func)(int , int)){while (low <= up){int mid = low + ((up-low)>>1);if (func(val, arr2[mid])) low = mid+1;else up = mid-1;}return low;}int getLIS(int n, bool (*func)(int, int)){int j = 0;arr2[0] = arr1[0];for (int i = 1; i < n; i++){if (func(arr1[i], arr2[j])) arr2[++j] = arr1[i];else arr2[biSearch(0, j, arr1[i], func)] = arr1[i];}return j+1;}int main(){int n;while (scanf("%d", &n) != EOF){for (int i = 0; i < n; i++){scanf("%d", &arr1[i]);}printf("%d\n", n-max(getLIS(n, larEqu), getLIS(n, smaEqu)));}return 0;}
然后是O(n)的时间效率的算法。
就是因为只有1,2,3,这三个数据,故此可以分开窗口,分别记录1, 2, 3 的数据段,在利用上面单调队列的思想的时候,就可以不使用二分法了,而是直接插入就可以了,故此省去了lgn的时间,时间效率就优化到O(n)了。
这个算法卡了我的地方就是下标的问题,老是无法准确记录窗口下标的,故此这里使用个特殊的记录下标的方法,看代码就好像是个O(n*n)的算法,因为循环中有循环,但是大家仔细看,其实这是个O(n)算法,为什么呢?因为循环中的循环总共只是搜索了一遍n个数,无需重复搜索。
#include <stdio.h>const int MAX_N = 30000;int arr1[MAX_N], arr2[MAX_N];inline int max(int a, int b) { return a > b? a : b; }int getLIS(int n){int j = 0, one = 0, two = 0;arr2[0] = arr1[0];for (int i = 1; i < n; i++){if (arr1[i] >= arr2[j]){arr2[++j] = arr1[i];}else{if (arr1[i] == 1){while (arr2[one] < 2 && one < j) one++;arr2[one] = arr1[i];}else{while (arr2[two] < 3 && two < j) two++;arr2[two] = arr1[i];}}}return j+1;}int getLDS(int n){int j = 0, two = 0, thr = 0;arr2[0] = arr1[0];for (int i = 1; i < n; i++){if (arr1[i] <= arr2[j]) arr2[++j] = arr1[i];else{if (arr1[i] == 3){while (arr2[thr] > 2 && thr < j) thr++;arr2[thr] = arr1[i];}else{while (arr2[two] > 1 && two < j) two++;arr2[two] = arr1[i];}}}return j+1;}int main(){int n;while (scanf("%d", &n) != EOF){for (int i = 0; i < n; i++){scanf("%d", &arr1[i]);}printf("%d\n", n-max(getLIS(n), getLDS(n)));}return 0;}
1 0
- POJ 3670 Eating Together 二分解法O(nlgn)和O(n)算法
- POJ 3670 Eating Together (①O(n)的dp,②最长字段和)
- poj 3670 Eating Together LIS+二分
- poj 3670 Eating Together
- POJ 3670 (Eating Together)
- 求a^n的O(nlgn)算法
- [算法]Fibonacci数列O(n)和O(lgn)的解法
- POJ 3670 Eating Together LIS最长递增子序列+二分查找 nlogn算法
- POJ 3670 Eating Together(LIS)
- poj 3670 Eating Together dp
- poj 3670 Eating Together LIS
- POJ 3670 Eating Together(LIS+nlogn算法)
- 贪心算法;部分背包问题;快速排序O(nlgn);贪心算法O(n);
- C++ Fibonacci数列 O(2^n) 和 O(n)解法
- poj 3670 Eating Together
- POJ:3670 Eating Together(动态规划)
- POJ 3670 Eating Together (DP)
- POJ 3670 Eating Together(dp)
- 关于“using namespace std”
- 实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化(三)
- C++中虚函数、虚表、虚指针实例讲解
- 几道简单题的巧妙解题思维-nyoj860
- Android中的Handler的post方法详解
- POJ 3670 Eating Together 二分解法O(nlgn)和O(n)算法
- ACM练级日志: POJ 1389
- (张龙讲学)java web学习---jsUnit、Ajax、JQuery
- hdu 4289 Control(网络流 最大流+拆点)(模板)
- ACM练级日志: POJ 1376
- 关于Android ViewPager与资源文件的矛盾关系
- EXC_ARM_DA_ALIGN问题
- Spark&Spark性能调优实战
- module.exports 还是 exports?