【问题标题】:Find the LIS with the maximum sum找到总和最大的 LIS
【发布时间】:2018-04-24 22:41:00
【问题描述】:

我有这段代码用于查找最长递增子序列 (LIS),但是当我测试我的代码时,我没有得到最大和,例如:

如果我输入 20 1 4 3 10 答案是 1 3 10,但我需要 1 4 10 这是我的 C 代码:

#include <stdio.h>
#include <stdlib.h>

#define INT_INF 1000

int search_replace(int *lis, int left, int right, int key) {
    int mid;

    for (mid = (left+right)/2; left <= right; mid = (left+right)/2) {
            if (lis[mid] > key) {
                    right = mid - 1;
            } else if (lis[mid] == key) {
                    return mid;
            } else if (mid+1 <= right && lis[mid+1] >= key) {
                    lis[mid+1] = key;
                    return mid+1;
            } else {
                    left = mid + 1;
            }
    }
    if (mid == left) {
            lis[mid] = key;
            return mid;
    }
    lis[mid+1] = key;
    return mid+1;
}

int main() {
    int size, i;

    scanf(" %d", &size);

    int A[size];

    for(i = 0; i < size; i++){
        scanf(" %d", &A[i]);
    }

    int tmp, lis_length = -1;
    int *answer;
    int LIS[size];
    int index[size];

    LIS[0] = A[0];
    for (i = 1; i < size; ++i) {
            LIS[i] = INT_INF;
    }

    for (i = 1; i < size; ++i) {
            index[i] = search_replace(LIS, 0, i, A[i]);
            if (lis_length < index[i]) {
                    lis_length = index[i];
            }
    }

    answer = (int*) malloc((lis_length+1) * sizeof(int));
    for (i = size-1, tmp = lis_length; i >= 0; --i) {
            if (index[i] == tmp) {
                    answer[tmp] = A[i];
                    --tmp;
            }
    }

    printf("LIS: ");
    for (i = 0; i < lis_length+1; ++i) {
            printf("%d ", answer[i]);
    }
    printf("\n");

    return 0;
}

第一个输入是数组中元素的数量。

我已经尝试过这个帖子:Find the Longest Increasing Subsequence with the Maximum Sum,还有其他几个,但没有成功。

【问题讨论】:

    标签: c algorithm lis


    【解决方案1】:

    我分析了您的代码并发现了您的问题:您没有找到最大总和的 lis 的代码,您只有简单的 lis 搜索。我已经添加了缺失的部分,现在代码可以正常工作了。另外,我编写了自己的解决方案,使用了另一种 lis 搜索算法,没有使用二分搜索。

    注意:(left+right)/2求中间值的方法,有问题-Nearly All Binary Searches and Mergesorts are Broken

    你的代码加上我的补充:

    #include <stdio.h>
    #include <stdlib.h>
    #include <limits.h>
    
    #define INT_INF 1000
    
    int search_replace(int *lis, int left, int right, int key) {
        int mid;
        for (mid = (left+right)/2; left <= right; mid = (left+right)/2) {
            if (lis[mid] > key) {
                right = mid - 1;
            } else if (lis[mid] == key) {
                return mid;
            } else if (mid+1 <= right && lis[mid+1] >= key) {
                lis[mid+1] = key;
                return mid+1;
            } else {
                left = mid + 1;
            }
        }
        if (mid == left) {
            lis[mid] = key;
            return mid;
        }
        lis[mid+1] = key;
        return mid+1;
    }
    
    int main() {
        int size, i;
    
        scanf(" %d", &size);
    
        int A[size];
    
        for(i = 0; i < size; i++){
            scanf(" %d", &A[i]);
        }
    
        int tmp, lis_length = -1;
        int LIS[size];
        int index[size];
    
        LIS[0] = A[0];
        for (i = 1; i < size; ++i) {
            LIS[i] = INT_INF;
        }
    
        for (i = 1; i < size; ++i) {
            index[i] = search_replace(LIS, 0, i, A[i]);
            if (lis_length < index[i]) {
                lis_length = index[i];
            }
        }
        
        //////// my addition starts
        int max, j;
        // INT_MAX - the maximum number of the integer type.
        // The "limits.h" header is needed for this.
        int prev = INT_MAX;
        int answer[lis_length + 1];
        // Iterating through the "index" values.
        // On the each iteration, the checking all sequences 
        // with the same length
        // and determining the max value among them.
        // Starts from the lis_length and goes to the zero.
        for(i = lis_length; i >= 0; i--) {
            max = INT_MIN;
            for(j = 0; j < size; j++) {
                if(    index[j] == i 
                    && A[j] > max 
                    && A[j] < prev) {
                        
                    max = A[j];
                }
            }
            answer[i] = max;
            prev = max;
        }
        //////// my addition ends
    
        printf("LIS: ");
        for (i = 0; i < lis_length+1; ++i) {
            printf("%d ", answer[i]);
        }
        printf("\n");
    
        return 0;
    }
    

    这是我使用 cmets 的解决方案。

    我用这个algorithm 来确定lis。如果需要,可以提出问题。

    #include <stdio.h>
    #include <limits.h>
    
    int main() {
        int size = 0;
        int arr_nums[100];
        // Initialize all array values to the one. This is the GCC feature.
        int seq_lens[100] = {[0 ... 99] = 1};
    
        // Gets input numbers.
        while(scanf("%d", arr_nums + size) == 1) {
            size++;
        }
        // Fill the seq_lens array with sequences's lenghts.
        int i, j;
        int lis_num = 1;
        for(i = 1; i < size; i++) {
            for(j = 0; j <= i; j++) {
                if(     arr_nums[i] > arr_nums[j] 
                    && (seq_lens[j] + 1 > seq_lens[i])) {
    
                        seq_lens[i] = seq_lens[j] + 1;
                }
            }
            // Finding the LIS number (the maximum sequence length).
            // If the previous LIS number is lesser then current, 
            // change it to the current.
            if(lis_num < seq_lens[i])
                lis_num = seq_lens[i];
        }
    
        // Finding the LIS with the maximum sum
        int max;
        // INT_MAX - the maximum number of the integer type.
        // The "limits.h" header is needed for this.
        int prev = INT_MAX;
        int lis_arr[lis_num];
        // Iterating through the seq_lens values.
        // On the each iteration, the checking all sequences with the same length
        // and determining the max value among them.
        // Starts from the LIS (the longest sequence number) 
        // and goes to the one (the minimum possible sequence number).
        for(i = lis_num; i > 0; i--) {
            max = INT_MIN;
            for(j = 0; j < size; j++) {
                if(    seq_lens[j] == i 
                    && arr_nums[j] > max 
                    && arr_nums[j] < prev) {
                        
                    max = arr_nums[j];
                }
            }
            lis_arr[i - 1] = max;
            prev = max;
        }
    
        printf("The longest increasing sequence number is:\n%d\n", lis_num);
    
        puts("\nThe longest increasing sequence with the max sum is: ");
        for(i = 0; i < lis_num; i++) {
            printf("%d ", lis_arr[i]);
        }
        puts("");
    
        return 0;
    }
    

    输入

    0 8 4 12 2 10 6 14 1 9 5 13 3 11 7 15
    

    输出

    The longest increasing sequence number is:
    6
    
    The longest increasing sequence with the max sum is: 
    0 4 6 9 13 15 
    

    【讨论】:

      猜你喜欢
      • 2021-05-26
      • 1970-01-01
      • 1970-01-01
      • 2013-11-12
      • 2012-11-08
      • 2022-12-12
      • 2014-01-07
      • 1970-01-01
      • 2018-09-10
      相关资源
      最近更新 更多