2018南京大学夏令营机试第一题

(题目来自tonygsw)

题目大意:

就是输入一个N*N的矩阵,找出在矩阵中,所有元素加起来之和最大的子矩阵。

例如在    

0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 2

这样一个4*4的矩阵中,元素之和最大的子矩阵为  

9 2
-4 1
-1 8

它们之和为15。 

输入 n,m及n*m矩阵

输出 最大和

思路:

这是一道经典DP(动态规划题目)

首先思考我们学过的简单的最大字段和问题

若想找到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;
}

   说了这么多,这跟最大子矩阵有什么关系呢?当然有关系啦!

   二维就是一维的扩展,把二维压扁不就变成一维了吗?

   我们假设所求N*N的矩阵的最大子矩阵是从i列到j列,q行到p行,如下图所示(假设下标从1开始)

  a[1][1]  a[1][2]  ······  a[1][i]  ······  a[1][j]   ······  a[1][n]

  a[2][1]  a[2][2]  ······  a[2][i]  ······  a[2][j]   ······  a[2][n]

                  ······

  a[q][1]  a[q][2]  ······  a[q][i]  ······  a[q][j]  ······  a[q][n]

                  ······

  a[p][1]  a[p][2]  ······  a[p][i]  ······  a[p][j]  ······  a[p][n]

                  ······

  a[n][1]  a[n][2]  ······  a[n][i]  ······  a[n][j]  ······  a[n][n]

  

       最大子矩阵就是图示红色部分,

       如果把最大子矩阵同列的加起来,我们可以得到一个一维数组{a[q][i]+······+a[p][i] , ······ ,a[q][j]+······+a[p][j]} ,

       现在我们可以看出,这其实就是一个一维数组的最大子段问题。

       如果把二维数组看成是纵向的一维数组和横向的一维数组,那问题不就迎刃而解了吗?

       把二维转换成了我们刚刚解决了的问题。

       计算列子段和的大致过程:

     2018南京大学夏令营机试第一题_第1张图片2018南京大学夏令营机试第一题_第2张图片2018南京大学夏令营机试第一题_第3张图片

 

代码:

#include 
#include 
using namespace std;

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

int main()
{
    int n,m,i,j,k,maxsubrec,maxsubarr;
    int dp[101][101],arr[101];
    while(cin>>n>>m)
    {    //输入矩阵 
         for(i=0;i>dp[i][j];
        //初始化最大和为0 
         maxsubrec = 0;
         //从上到下,依次计算 
         for(i=0;i maxsubrec) maxsubrec = maxsubarr;//取子段和最大值 
             }
         }
         cout<

 

你可能感兴趣的:(面试/笔试)