蒜国地域是一个 n 行 m 列的矩阵,下标均从 1开始。蒜国有个美丽的城堡,在坐标 (n,m)上,蒜头君在坐标 (1,1) 的位置上。蒜头君打算出发去城堡游玩,游玩结束后返回到起点。在出发去城堡的路上,蒜头君只会选择往下或者往右走,而在返回的路上,蒜头君只会选择往上或者往左走,每次只能走一格。已知每个格子上都有一定数量的蒜味可乐,每个格子至多经过一次。
现在蒜头君请你来帮他计算一下,如何计划来回行程,可以收集到最多的蒜味可乐。
输入格式
第一行输入两个整数 n,m(1≤n,m≤50),表示蒜国是一个 n行 m 列的矩阵。
接下来输入 n 行,每行输入 m 个整数,代表一个 n×m 的矩阵,每个整数代表对应位置上的蒜味可乐数量,每行的每两个整数之间用一个空格隔开。其中蒜头君的位置和城堡的位置上没有蒜味可乐,用 0 表示,其余位置上的整数范围在 [1,100] 内。
输出格式
输出一行,输出一个整数,表示蒜头君在来回路上能收集到的蒜味可乐的最大值。
样例输入
3 3 0 2 9 4 8 6 2 7 0
样例输出
36
#include<iostream> #include<cstring> using namespace std; struct pos { int i,j; pos(int ii,int jj) { i = ii; j = jj; } }; int n,m; int mp[51][51]; int dp[51][51][51][51]; bool check(pos a) { return (a.i >= 0 && a.i < n && a.j >= 0 && a.j < m); } void init() { memset(dp,-1,sizeof(dp)); memset(mp,0,sizeof(mp)); } int work(pos a,pos b) { pos ta = pos(a.i-1,a.j); pos tb = pos(a.i,a.j-1); pos tc = pos(b.i-1,b.j); pos td = pos(b.i,b.j-1); bool ca = check(ta),cb = check(tb),cc = check(tc),cd = check(td); int ans = -9999999; if (a.i == 0 && a.j == 0 && b.i == 0 && b.j == 0) { return 0; } if (a.i == b.i && a.j == b.j) { if (ca && cc) { if (dp[ta.i][ta.j][tc.i][tc.j] == -1) { int tp1 = work(ta,tc); dp[ta.i][ta.j][tc.i][tc.j] = tp1; ans = max(ans,tp1+mp[a.i][a.j]); } else ans = max(ans,dp[ta.i][ta.j][tc.i][tc.j]+mp[a.i][a.j]); } if (ca && cd) { if (dp[ta.i][ta.j][td.i][td.j] == -1) { int tp2 = work(ta,tc); dp[ta.i][ta.j][td.i][td.j] = tp2; ans = max(ans,tp2+mp[a.i][a.j]); } else ans = max(ans,dp[ta.i][ta.j][td.i][td.j]+mp[a.i][a.j]); } if (cb && cc) { if (dp[tb.i][tb.j][tc.i][tc.j] == -1) { int tp3 = work(tb,tc); dp[tb.i][tb.j][tc.i][tc.j] = tp3; ans = max(ans,tp3+mp[a.i][a.j]); } else ans = max(ans,dp[tb.i][tb.j][tc.i][tc.j]+mp[a.i][a.j]); } if (cb && cd) { if (dp[tb.i][tb.j][td.i][td.j] == -1) { int tp4 = work(tb,td); dp[tb.i][tb.j][td.i][td.j] = tp4; ans = max(ans,tp4+mp[a.i][a.j]); } else ans = max(ans,dp[tb.i][tb.j][td.i][td.j]+mp[a.i][a.j]); } } else { if (ca && cc) { if (dp[ta.i][ta.j][tc.i][tc.j] == -1) { int tp1 = work(ta,tc); dp[ta.i][ta.j][tc.i][tc.j] = tp1; ans = max(ans,tp1+mp[a.i][a.j]+mp[b.i][b.j]); } else ans = max(ans,dp[ta.i][ta.j][tc.i][tc.j]+mp[a.i][a.j]+mp[b.i][b.j]); } if (ca && cd) { if (dp[ta.i][ta.j][td.i][td.j] == -1) { int tp2 = work(ta,tc); dp[ta.i][ta.j][td.i][td.j] = tp2; ans = max(ans,tp2+mp[a.i][a.j]+mp[b.i][b.j]); } else ans = max(ans,dp[ta.i][ta.j][td.i][td.j]+mp[a.i][a.j]+mp[b.i][b.j]); } if (cb && cc) { if (dp[tb.i][tb.j][tc.i][tc.j] == -1) { int tp3 = work(tb,tc); dp[tb.i][tb.j][tc.i][tc.j] = tp3; ans = max(ans,tp3+mp[a.i][a.j]+mp[b.i][b.j]); } else ans = max(ans,dp[tb.i][tb.j][tc.i][tc.j]+mp[a.i][a.j]+mp[b.i][b.j]); } if (cb && cd) { if (dp[tb.i][tb.j][td.i][td.j] == -1) { int tp4 = work(tb,td); dp[tb.i][tb.j][td.i][td.j] = tp4; ans = max(ans,tp4+mp[a.i][a.j]+mp[b.i][b.j]); } else ans = max(ans,dp[tb.i][tb.j][td.i][td.j]+mp[a.i][a.j]+mp[b.i][b.j]); } } return ans; } int main() { init(); cin >> n >> m; for (int i=0;i<n;i++) { for (int j=0;j<m;j++) { cin >> mp[i][j]; } } cout << work(pos(n-1,m-1),pos(n-1,m-1)); return 0; }
代码写的很长,其中判断那一块可以精简一下,值得关注的还是 check 函数的范围判断以及矩阵多阶段问题的优化,途中这两个人永远处在同一条斜率为 1 的直线上。通过上面的结论可以极大的优化需要处理的地图点的问题。