循环数组的最大字串和Maximal-sum Subsequence

Posted neilthang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了循环数组的最大字串和Maximal-sum Subsequence相关的知识,希望对你有一定的参考价值。

【循环数组的最大字串和】Maximal-sum Subsequence

PROBLEM

题目描述

给一个 N×N 的矩阵 M,可以取连续的一段数(必须是横着或者竖着或者斜着,这个矩阵是循环的,具体如下)。要求找到一个子序列,使得这个序列的和最大。
技术分享图片
对于 N=8 的矩阵,如下序列都是合法的:
? M2,1,M2,2,M2,3,M2,4,M2,5,M2,6,M2,7,M2,8.
? M2,2,M2,3,M2,4.
? M2,6,M2,7,M2,8,M2,1,M2,2.
? M4,3,M5,3,M6,3,M7,3.
? M1,2,M2,3,M3,4,M4,5.
? M2,4,M3,3,M4,2,M5,1.
? M3,3,M4,2,M5,1,M1,5. (按样例理解是M8,6 ,emmmmm)
? M5,6.
一个元素不可取多次,取的必须是连续的一段。
可以什么都不取(即答案为 0)。

输入

第一行一个数 T (T≤30),表示数据组数。
每一组数据第一行为一个正整数 N (1≤N≤1000)。
接下来 N 行每行 N 个数表示这个矩阵。(每个元素大小在 ?32768 到 32767 之间)

输出

每组数据一行表示最大的序列和。

样例输入

1
4 
8 6 6 1
-3 4 0 5
4 2 1 9
1 -9 9 -2

样例输出

24

提示

样例解释:选取序列 M3,4,M4,3,M1,2。

SOLUTION

题面好像有点问题,应该按照提示(样例)来理解。
首先你要会如何求数组的最大字串和。
然后循环数组最大字串和 = max(数组求和+数组元素取反后的最大字串和,原数组的最大字串和)
最后每行每列以及所有斜向上的答案取最值即可。

CODE

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN = 2005;

int martix[MAXN][MAXN];

int dp[MAXN];

int py(int x,int n){
    while (x<0)x+=n;
    while (x>=n)x-=n;
    return x;
}

int cal(int arr[],int n) {
    int sum = 0;
    memset(dp, 0, sizeof(dp));
    sum = dp[0] = arr[0];
    for (int i = 1; i < n; i++) {
        dp[i] = max(arr[i], dp[i-1]+arr[i]);
        sum += arr[i];
    }
    int ans = 0;
    for (int i = 1; i < n; i++) {
        if (dp[i] > dp[ans]) {
            ans = i;
        }
    }
    int ans1 =  dp[ans];
    for (int i = 0; i < n; i++) {
        arr[i] = -arr[i];
    }
    memset(dp, 0, sizeof(dp));
    dp[0] = arr[0];
    for (int i = 1; i < n; i++) {
        dp[i] = max(arr[i], dp[i-1]+arr[i]);
    }
    ans = 0;
    for (int i = 1; i < n; i++) {
        if (dp[i] > dp[ans]) {
            ans = i;
        }
    }
    int ans2 = dp[ans];
    return max(ans1,ans2+sum);
}

int main(){
    int T;
    for(scanf("%d",&T);T;T--){
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                scanf("%d",&martix[i][j]);
            }
        }
        int ans = 0;
        for(int i=0;i<n;i++){
            int carry[MAXN];
            for(int j=0;j<n;j++){
                carry[j] = martix[i][j];
            }
            ans = max(ans,cal(carry,n));
            for(int j=0;j<n;j++){
                carry[j] = martix[j][i];
            }
            ans = max(ans,cal(carry,n));
            for(int j=0;j<n;j++){
                carry[j] = martix[py(i-j,n)][py(j,n)];
            }
            ans = max(ans,cal(carry,n));
            for(int j=0;j<n;j++){
                carry[j] = martix[py(i-j,n)][py(n-j-1,n)];
            }
            ans = max(ans,cal(carry,n));
        }
        cout<<ans<<endl;
    }
}

以上是关于循环数组的最大字串和Maximal-sum Subsequence的主要内容,如果未能解决你的问题,请参考以下文章

关于Kmp

SPOJ REPEATS - Repeats - 后缀数组

poj 44 字串和dp

最大子串和问题最小子串覆盖问题

UPC3463: Maximal-sum Subsequence

Leetcode53.最大子串和(简单)76.最小子串覆盖(困难)3. 最长子串不重复问题(中等)