問題鏈接:
問題分析:
題目要求很簡單,遊客只能自左向右行走,但是可以南北隨意移動。然後給每段街道劃分數值,要求找出在這樣的情況下的最大數值。
藉助下圖進一步分析題目意思:
如上圖所示:典型的貪心問題,題目要求最終解所得數值最大,故每次選擇時都要保證選擇的是當前可供選項裏的最大值。如上例所示最優解必定是17,-3,36,34,-8的子集,因此此題的解也就可以用求解最大子數組的方法完成了。
問題求解:
法一:
#include<iostream>
using namespace std;
#define INT -1e7;
int maxCrossingSubarray(int *A, int lo, int mi, int hi){
int leftSum, rightSum;
leftSum = INT;
rightSum = INT;
int sum = 0;
for(int i = mi; i >= lo; i--){
sum += A[i];
if(sum > leftSum){
leftSum = sum;
}
}
sum = 0;
for(int i = mi+1; i <= hi; i++){
sum += A[i];
if(sum > rightSum){
rightSum = sum;
}
}
return leftSum + rightSum;
}
int maxSubarray(int *A, int lo, int hi){
if(lo == hi) return A[lo];
int mi = (lo+hi) / 2;
int left = maxSubarray(A, lo, mi);
int right = maxSubarray(A, mi+1, hi);
int cros = maxCrossingSubarray(A, lo, mi, hi);
if(left >= right && left >= cros)
return left;
else if(right >= left && right >= cros)
return right;
else return cros;
}
int main(){
int n, m;
cin >> n >> m;
int ars[n][m];
int val[m];
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
cin >> ars[i][j];
for(int i = 0; i < m; i++){//找出每一列最大值
int max = ars[0][i];
for(int j = 1; j < n; j++){
if(max < ars[j][i])
max = ars[j][i];
}
val[i] = max;
}
//轉變爲求最大子數組問題
cout << maxSubarray(val, 0, m-1);
return 0;
}
法二:
#include<iostream>
using namespace std;
int maxSubarray(int *A, int len){
int max = 0, sum = 0;
for(int i = 0; i < len; i++){
sum += A[i];
if(sum > 0){
if(sum > max)
max = sum;
} else
sum = 0;
}
return max;
}
int main(){
int n, m;
cin >> n >> m;
int ars[n][m];
int val[m];
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
cin >> ars[i][j];
for(int i = 0; i < m; i++){//找出每一列最大值
int max = ars[0][i];
for(int j = 1; j < n; j++){
if(max < ars[j][i])
max = ars[j][i];
}
val[i] = max;
}
//轉變爲求最大子數組問題
cout << maxSubarray(val, m);
return 0;
}