计蒜客:最大子阵

计蒜客:最大子阵_第1张图片

这道题是个二维数组的,我们看看:如果有一个一维数组a[n],如何找出连续的一段,使其元素之和最大呢?

例如:int a[]= {1,2, -3, 4, -2, 5,-3,-1, 7,4, -6 };  max=14。

1.穷举法(有三层循环,所以n很大时不能使用这种方法。

int main()
{
    int a[]={1 ,2, -3, 4, -2, 5 ,-3 ,-1, 7,4, -6 };
    int n=11,i,j,k,max=-INF;
    int sum  = 0;
    for(i=0; i max)    max = sum;
        }
    }
    cout<

2、带记忆的递推法

int main()
{
    int a[]= {1,2, -3, 4, -2, 5,-3,-1, 7,4, -6 };
    int record[20],sum=0,n=11;
    int i,j,max;
    record[0] = 0;
    for(i=1; i<=n; i++)
        record[i] = record[i-1] + a[i];  //用record记录a[i]前i个的和
    max = -INF;
    for(i=1; i<=n; i++)
    {
        for(j=0; j max)    max = sum;
        }
    }
    cout<

3、动态规划

分析一下最优子结构,若想找到n个数的最大子段和,那么要找到n-1个数的最大子段和,这就出来了。我们用b[i]来表示a[0]...a[i]的最大子段和,b[i]无非有两种情况
    (1)最大子段一直连续到a[i]  

    (2)以a[i]为首的新的子段。

由此我们可以得到b[i]的状态转移方程:

b[i]=max{ b[i-1]+a[i],a[i] }

最终我们得到的最大子段和为max{ b[i], 0<=i

int MaxSubArray(int a[],int n)
{
    int i,b = 0,sum = 0;
    for(i = 0;i < n;i++)
    {
        if(b>0)                // 若a[i]+b[i-1]会减小
            b += a[i];        // 则以a[i]为首另起一个子段
        else
            b = a[i];
        if(b > sum)
            sum = b;
    }
    return sum;
}

int main () {
	  int a[]= {1,2, -3, 4, -2, 5,-3,-1, 7,4, -6 };
	  int ans = MaxSubArray(a,11);
	  cout<

于是乎这道题中二维数组的每一列也可以看做一个一维数组。结合上面的1和3:

#include 
#include 
using namespace std;
const int INF = 0x3f3f3f3f;

int maxsub(int a[],int n)
{
    int i,max=-INF,b=0;
    for(int i=0; i0) b+=a[i];
        else b=a[i];
        if(b>max) max = b;
    }
    return max;
}

int main()
{
    int n,m,res,max=-INF;
    int f[100][100],arr[100];
    cin>>n>>m;
    for(int i=0; i>f[i][j];

    for(int i=0; i=0; k--)
                arr[k]+=f[j][k];
            res = maxsub(arr,m);
            if(max

 

你可能感兴趣的:(dp,背包)