NYOJ-104最大和
我看了好多博客,都是拿一维的做基础,一维的比较简单,所以要把二维的化成一维的,一维的题目大意:给了一个序列,求那个子序列的和最大,这时候就可以用dp来做,首先dp[i]表示第i个数能构成的最大子序列和,所以dp[i] = dp[i - 1] > 0 ? dp[i - 1] + dp[i] : dp[i]; 这个比较好理解,但是二维的,貌似想不起来这样写了。但是,如果转换一下,还是可以的,方法如下:
1. 将行划分,划分的结果为所有情况
2.将划分好的“新行”进行合并成“一行”,
3.对“一行”进行一维的求最大子段和
举个例子:
0 -2 -7 0
9 2 -6 2
-4 1 -4 7
-1 8 0 -2
我们分别用i j表示起始行和终止行,遍历所有的可能:
for(i=1;i<=n;i++)
for(j=i;j<=n;j++) {}
我们考察其中一种情况 i=2 j=4,这样就相当与选中了2 3 4三行,求那几列的组合能获得最大值,由于总是 2 3 4行,所以我们可以将这3行”捆绑”起来,变为求 4(9-4-1),11(8+2+1),-10(-6-4+0),7(7+2-2)的最大子段和,ok,问题成功转化为一维的情况!
注意:代码中还有一个地方需要注意,就是读入原始数据的时候,要处理一下,再保存到数组中,每一行的数据都不是原来的数据,而是加上同一列以上各行的数据,这样以来,在合并求和的时候就比较方便了。比如求2,3两行的和,只要第三行的值减去第一行的值就行了
代码如下:
1 #include<iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define inf 99999999 6 using namespace std; 7 const int n = 105; 8 int map[n][n]; 9 int temp[n]; 10 int ans; 11 //一维序列求最大和 12 int find_max(int a[], int m) 13 { 14 int max_sum = -inf; 15 int res = 0; 16 for (int k = 1; k <= m; k++) 17 { 18 if (res > 0) 19 res += a[k]; 20 else 21 res = a[k]; 22 if (res > max_sum) 23 max_sum = res; 24 } 25 return max_sum; 26 } 27 int main() 28 { 29 int n; 30 cin >> n; 31 while (n--) 32 { 33 memset(map, 0, sizeof(map)); 34 int r, c; 35 int t; 36 cin >> r >> c; 37 for (int i = 1; i <= r; i++) 38 { 39 for (int j = 1; j <= c; j++) 40 { 41 cin >> map[i][j]; 42 map[i][j] += map[i - 1][j];//处理一下 43 } 44 } 45 ans = -inf; 46 for (int i = 0; i < r; i++) 47 { 48 for (int j = i + 1; j <= r; j++)//枚举所有情况 49 { 50 for (int k = 1; k <= c; k++)//将“新和”计算出来保存到数组temp中 51 { 52 temp[k] = map[j][k] - map[i][k]; 53 } 54 //找到这段当中的最大和 55 t = find_max(temp, c); 56 if (t > ans) 57 ans = t;//ans全局变量保存结果,即最大值 58 } 59 } 60 cout << ans << endl; 61 } 62 63 return 0; 64 }