Solution to CLRS Chapter 4

来源:互联网 发布:mac鼠标能点右键吗 编辑:程序博客网 时间:2024/06/16 21:18

这一章主要介绍了几个divide-and-conquer的例子,并且引入了对递归算法的复杂度进行刻画的数学工具,这章工具数学性很强,所以数学部分打算以后遇到了再回头来看,不过那个master theorem真的好方便啊!

4.1-1
用divide-and-conquer处理最大连续子序列和,在conquer的时候,涉及3个sum之间的比较:
left-sum,right-sum,cross-sum,其中cross-sum必须要包含a[mid],a[mid+1]两个点,由于整个序列都是负数,所以cross-sum是最小的(加的越多越下),先排除,这样,剩下left-sum和right-sum本质上是就是找左右区间中最大的那个元素,所以,最后的结果一定返回的是[1…n]中,最大的负数

4.1-2
brute-force算法,就是要枚举每一种买股票的可能,这可以通过枚举买进时间i,卖出时间j来实现,这样的复杂度,已经达到theta(n^2)了,所以,在确定了区间[i,j]的时候,需要一个常数级算法,求出区间[i,j]的和,这个可以用一个预处理,得到一个sum[]数组,sum[i]表示前i项的和,那么区间[i,j]的和就可以表示成sum[j]-sum[i-1]
pseudocode:

BRUTE-FORCE-MAXIMUN-SUBARRAY        sum[0] = 0;        for i = 1 : N                sum[i] = sum[i-1] + a[i]        maxSum = -INF        for i = 1 : N                for j = i : N                        if sum[j] - sum[i-1] > maxSum                                maxSum = sum[j] - sum[i-1]                                startPoint = i;                                endPoint = j;        return (maxSum, startPoint, endPoint)

4.1-3
这题是判断brute-force算法和用divide-and-conquer paradigm的性能的分界点,然后用这个来优化recursive版本算法的性能,换角度说也就是coarsen the leaves,这个思想在之前的merge sort 也用到了。
下面用C++实现一下这个比较:(比较方法是测试规模为10000的数据)
我电脑测试的时候,从n=1开始,就是divide-and-conquer更加优秀………………
C++ code:

#include <iostream>#include <cstdlib>#include <ctime>#include <cstring>#include <cstdio>using namespace std;const int INF = 0x7fffffff;const int MAX_N = 1000000 + 3;int A[MAX_N];int CrossSum (int *A, int l, int mid, int r) {        int left_max = -INF, left_sum = 0;        int right_max = -INF, right_sum = 0;        for (int i = mid; i >= l; --i) {                left_sum += A[i];                left_max = max(left_max, left_sum);        }        for (int i = mid+1; i <= r; ++i) {                right_sum += A[i];                right_max = max(right_max, right_sum);        }        return left_max + right_max;}int RecursiveMaxSub (int *A, int l, int r) {        if (l == r)                 return A[l];        int mid = (l + r) / 2;        int left_sum = RecursiveMaxSub(A, l, mid);        int right_sum = RecursiveMaxSub(A, mid+1, r);        int cross_sum = CrossSum(A, l, mid, r);        int maxSum = left_sum;        if (right_sum > maxSum)                maxSum = right_sum;        if (cross_sum > maxSum)                maxSum = cross_sum;        return maxSum;}int sum[MAX_N];int BruteForceMaxSub (int *A, int N) {        int i, j, maxSum = -INF;        sum[0] = 0;        for (i = 1; i <= N; ++i)                sum[i] = sum[i-1] + A[i];        for (i = 1; i <= N; ++i)                for (j = i; j <= N; ++j)                        if (sum[j] - sum[i-1] > maxSum)                                maxSum = sum[j] - sum[i-1];        return maxSum;}void getNewArray(int* A, int n) {        for (int i = 1; i <= n; ++i)                A[i] = rand() % 1000 - 500;}int main (int argc, char* argv[]) {        int n = 9;               srand(time(NULL));        getNewArray(A, n); //randomly get a new array        int time1 = clock();        int result1 = BruteForceMaxSub(A, n);        time1 = clock() - time1;        int time2 = clock();        int result2 = RecursiveMaxSub(A, 1, n);        time2 = clock() - time2;        if (result1 != result2)                cout << "Algorithm Error!" << endl;        //cout << "brute-force: " << time1 / CLOCKS_PER_SEC << " s   divide-and-conquer: " << time2 / CLOCKS_PER_SEC << " s" << endl;        cout << "brute-force: " << time1 << " clocks   divide-and-conquer: " << time2 << " clocks" << endl;        return 0;}

4.1-4
这个挺简单的,不允许empty array只会出现在所有的元素都是负数的情况下,由4.1-1知这种情况下,返回的一定是元素中最大的负数,所以,只要加一个判断-如果MaxSub返回的结果是负数,那么显然这个结果不如选取一个空串得到0,所以将所以返回负数的情况,特判改成0就可以了。

4.1-5
这道题就是动态规划的思想吧,hdu1003 Max Sum 就是这个题目,还有一个升级版是hdu1024
这里给出升级版:

#include <cstdio>#include <cstring>#include <algorithm>using std::max;const int MAX_N = 1000000 + 6;const int INF = 0x7fffffff;int dp[MAX_N];int a[MAX_N];int rmax[MAX_N];int main (int argc, char* argv[]) {#ifndef ONLINE_JUDGE    freopen("in.txt", "r", stdin);#endif    int n, m;    while (scanf("%d%d", &m, &n) != EOF) {        for (int i = 1; i <= n; ++i)            scanf("%d", a + i);        memset(dp, 0, sizeof(dp));        memset(rmax, 0, sizeof(rmax));        int ans = -INF;        int i, j;        for (i = 1; i <= m; ++i) {            ans = -INF;            for (j = i; j <= n; ++j) {                dp[j] = max(dp[j-1], rmax[j-1]) + a[j];                rmax[j-1] = ans;                ans = max(ans, dp[j]);            }        }        printf("%d\n", ans);    }    return 0;}

这一章有点奇怪,但感觉并不是无用,回头再看
4.2-1
4.2-2
4.2-3
4.2-4
4.2-5
4.2-6
4.2-7

以后遇到相关的计算再来看,现在对这个没什么概念

0 0
原创粉丝点击