zoukankan      html  css  js  c++  java
  • 《现代程序设计》9.9日课后总结

    邹老师的第一门课上小测了最大子矩阵的问题,课堂上只想到了O(n^2*m^2)的算法

    后来翻《编程之美》的时候翻到了这道题...今天下午研究了一下,到OJ上切了几道题,熟悉了动态规划在这个问题中的应用.

    一.最大子段和

    书上已经将这种思想讲的很透彻,对基本的最大子段和的练习可以参照hdu1003题http://acm.hdu.edu.cn/showproblem.php?pid=1003,唯一的一点变形是这道题要求求出最大字段的起始位置和终止位置.

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<algorithm>
     6 #define INF 0x3f3f3f3f
     7 using namespace std;
     8 const int maxn=100005;
     9 int map[maxn];
    10 int ans;
    11 int begin;
    12 int end;
    13 int n;
    14 void getmap()
    15 {
    16     for(int i=1;i<=n;i++)
    17     {
    18         cin>>map[i];
    19     }
    20 }
    21 void work()
    22 {
    23     int tempsum=0;
    24     int tmpbegin=1;
    25     for(int i=1;i<=n;i++)
    26     {
    27         tempsum+=map[i];
    28         if(tempsum>ans)
    29         {
    30             ans=tempsum;
    31             begin=tmpbegin;
    32             end=i;
    33         }
    34         if(tempsum<0)
    35         {
    36             tempsum=0;
    37             tmpbegin=i+1;
    38         }
    39         
    40     }
    41 }
    42 
    43 int main()
    44 {
    45     int T;
    46     cin>>T;
    47     for(int tt=1;tt<=T;tt++)
    48     {
    49         ans=-INF;
    50         cin>>n;
    51         getmap();
    52         work();
    53         cout<<"Case "<<tt<<":"<<endl;
    54         cout<<ans<<" "<<begin<<" "<<end<<endl;
    55         if(tt<T)
    56         {
    57             cout<<endl;
    58         }
    59     }
    60     return 0;
    61 }

    关于最大子段和有一种变形是最大m子段和,http://acm.hdu.edu.cn/showproblem.php?pid=1024,就是在原有的基础上求m段子段的和,这里建立动态规划方程,dp[i][j]表示前j个数(包括第j个数)组成i段的和的最大值,那么根据第j个数是否独立成组得到转移方程为dp[i][j]=max(dp[i-1][j-1]+a[j],dp[i-1][k]+a[j]),0<k<j,这里dp[i][]只和dp[i-1][]有关,用一维数组就可以表示,同时dp[i-1][k]表示1~j-1中构成i-1组的最大值,即前一组的值,那么可以在循环中求出,所以复杂度为O(n*m)

     1 /*
     2 dp[i][j]前j个数(包括第j个数,组成i组的和的最大值
     3 dp[i][j]=max(dp[i-1][j-1]+map[j],dp[i-1][k]+map[j]),0<k<j
     4 即根据第j个数是否单独成组划分状态
     5 前i组仅与前i-1组有关,这里用一维数组就好
     6 而dp[i-1][k]其实就是上一组中从0-j-1中划分为i-1组的最大值 
     7 */
     8 #include<iostream>
     9 #include<cstdio>
    10 #include<cstring>
    11 #include<cstdlib>
    12 #include<algorithm>
    13 #define INF 0x3f3f3f3f
    14 using namespace std;
    15 const int maxn=1000005;
    16 __int64 map[maxn];
    17 __int64 dp[maxn];
    18 __int64 prev[maxn];
    19 __int64 ans;
    20 int m;
    21 int n;
    22 void getmap()
    23 {
    24     dp[0]=0;
    25     prev[0]=0;
    26     for(int i=1;i<=n;i++)
    27     {
    28         scanf("%I64d",&map[i]);
    29         dp[i]=0;
    30         prev[i]=0;
    31     }
    32 }
    33 void work()
    34 {
    35     for(int i=1;i<=m;i++)
    36     {
    37         ans=-INF;
    38         for(int j=i;j<=n;j++)
    39         {
    40             dp[j]=max(dp[j-1],prev[j-1])+map[j];
    41             prev[j-1]=ans;
    42             ans=max(ans,dp[j]);
    43         }
    44     }
    45 }
    46 int main()
    47 {
    48     while(scanf("%d%d",&m,&n)!=EOF)
    49     {
    50         getmap();
    51         work();
    52         printf("%I64d
    ",ans);
    53     }
    54     return 0;
    55 }

    根据这道题那么poj2593,http://poj.org/problem?id=2593,就很容易解决了...就是将m替换为两段就好

     1 /*
     2 dp[i][j]前j个数(包括第j个数,组成i组的和的最大值
     3 dp[i][j]=max(dp[i-1][j-1]+map[j],dp[i-1][k]+map[j]),0<k<j
     4 即根据第j个数是否单独成组划分状态
     5 前i组仅与前i-1组有关,这里用一维数组就好
     6 而dp[i-1][k]其实就是上一组中从0-j-1中划分为i-1组的最大值 
     7 */
     8 #include<iostream>
     9 #include<cstdio>
    10 #include<cstring>
    11 #include<cstdlib>
    12 #include<algorithm>
    13 #define INF 0x3f3f3f3f
    14 using namespace std;
    15 const int maxn=1000005;
    16 int map[maxn];
    17 int dp[maxn];
    18 int prev[maxn];
    19 int ans;
    20 int m;
    21 int n;
    22 void getmap()
    23 {
    24     dp[0]=0;
    25     prev[0]=0;
    26     for(int i=1;i<=n;i++)
    27     {
    28         scanf("%d",&map[i]);
    29         dp[i]=0;
    30         prev[i]=0;
    31     }
    32 }
    33 void work()
    34 {
    35     for(int i=1;i<=m;i++)
    36     {
    37         ans=-INF;
    38         for(int j=i;j<=n;j++)
    39         {
    40             dp[j]=max(dp[j-1],prev[j-1])+map[j];
    41             prev[j-1]=ans;
    42             ans=max(ans,dp[j]);
    43         }
    44     }
    45 }
    46 int main()
    47 {
    48     while(scanf("%d",&n)!=EOF&&n)
    49     {
    50         m=2;
    51         getmap();
    52         work();
    53         printf("%d
    ",ans);
    54     }
    55     return 0;
    56 }

    二.最大子矩阵

    最大子矩阵的算法就是将第k列中第i行到j行的数的和求出,然后套用一维的算法就好

    我拿poj1050,http://poj.org/problem?id=1050,做了练习

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<algorithm>
     6 #define INF 0x3f3f3f3f
     7 using namespace std;
     8 const int maxn=105;
     9 int map[maxn][maxn];
    10 int sum[maxn][maxn];
    11 int ans;
    12 int n;
    13 void getmap()
    14 {
    15     for(int i=1;i<=n;i++)
    16     {
    17         for(int j=1;j<=n;j++)
    18         {
    19             cin>>map[i][j];
    20         }
    21     }
    22 }
    23 void getsum()
    24 {
    25     memset(sum,0,sizeof(sum));
    26     for(int i=1;i<=n;i++)
    27     {
    28         for(int j=1;j<=n;j++)
    29         {
    30             sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+map[i][j];
    31         }
    32     }
    33 }
    34 void work()
    35 {
    36     ans=-INF;
    37     for(int i=1;i<=n;i++)
    38     {
    39         for(int j=i;j<=n;j++)
    40         {
    41             int start=sum[j][n]-sum[i-1][n]-sum[j][n-1]+sum[i-1][n-1];
    42             int all=start;
    43             for(int k=n-1;k>=1;k--)
    44             {
    45                 if(start<0)
    46                 {
    47                     start=0;
    48                 }
    49                 start+=sum[j][k]-sum[i-1][k]-sum[j][k-1]+sum[i-1][k-1];
    50                 all=max(all,start);
    51             }
    52             ans=max(ans,all);
    53         }
    54     }
    55 }
    56 int main()
    57 {
    58     while(cin>>n)
    59     {
    60         getmap();
    61         getsum();
    62         work();
    63         cout<<ans<<endl;
    64     }
    65     return 0;
    66 }

    暂时只能想到这些,以后遇到该问题的变形,比如像课后扩展那样对于矩阵可以首尾相连,二维扩展到三维、四维等等的问题,我会继续在这里更新。

  • 相关阅读:
    Token_使用JWT生成token
    JSON Web Tokens(JWT)
    Hadoop 2.0 中的资源管理框架
    Hadoop 1.0 和 2.0 中的数据处理框架
    Hadoop 概述
    探索 OpenStack 之(17):计量模块 Ceilometer 中的数据收集机制
    探索 OpenStack 之(16):计量模块 Ceilometer 介绍及优化
    VMware + OpenStack: 从 Plugin 到 VIO (VMware Integrated OpenStack)的演进
    探索 OpenStack 之(15):oslo.messaging 和 Cinder 中 MessageQueue 消息的发送和接收
    探索 OpenStack 之(14):OpenStack 中 RabbitMQ 的使用
  • 原文地址:https://www.cnblogs.com/oldoldb/p/3312195.html
Copyright © 2011-2022 走看看