zoukankan      html  css  js  c++  java
  • 计蒜客:最大子阵

    这道题是个二维数组的,我们看看:如果有一个一维数组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<n; i++)
        {
            for(j=0; j<=i; j++)
            {
                sum = 0;
                for(k=j; k<=i; k++)
                    sum += a[k];
                if(sum > max)    max = sum;
            }
        }
        cout<<max<<endl;
        return 0;
    }

    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<i; j++)
            {
                sum = record[i] - record[j];
                if(sum > max)    max = sum;
            }
        }
        cout<<max<<endl;
        return 0;
    }

    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<n},Code:

    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<<ans<<endl;
    	return 0;
    }

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

    #include <iostream>
    #include <cstring>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    
    int maxsub(int a[],int n)
    {
        int i,max=-INF,b=0;
        for(int i=0; i<n; i++)
        {
            if(b>0) 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<n; i++)
            for(int j=0; j<m; j++)
                cin>>f[i][j];
    
        for(int i=0; i<n; i++)
        {
            memset(arr,0,sizeof(arr));
            for(int j=i; j<n; j++)
            {
                for(int k=0;k<m; k++)
                    arr[k]+=f[j][k];
                res = maxsub(arr,m);
                if(max<res) max = res;
            }
        }
        /*for(int i=0; i<n; i++)
        {
            memset(arr,0,sizeof(arr));
            for(int j=i; j<n; j++)
            {
                for(int k=m-1;k>=0; k--)
                    arr[k]+=f[j][k];
                res = maxsub(arr,m);
                if(max<res) max = res;
            }
        }*/
        cout<<max<<endl;
        return 0;
    }
    
  • 相关阅读:
    tyvj1117 拯救ice-cream
    codevs3410 别墅房间
    codevs1099 字串变换
    codevs1226 倒水问题
    codevs2449 骑士精神
    codevs1225 八数码难题
    Wikioi 3776 生活大爆炸版石头剪子布
    codevs1197 Vigenère密码
    枚举 + exgcd
    C++ 排序引用的优化
  • 原文地址:https://www.cnblogs.com/qie-wei/p/12094115.html
Copyright © 2011-2022 走看看