仍是多线程dp,这次直接斜着读入,方便写dp方程。
以6×4的图为例,读入顺序如表(从左至右,从上至下,不用管那些0)
for(int i = 1; i <= m; ++i) for(int j = 1; j <= n; ++j)
read(map[i+j-1][i]);
- | - | - | - | - | - | - | - | - |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | (1,4) | (2,4) | (3,4) | (4,4) | (5,4) | (6,4) |
0 | 0 | (1,3) | (2,3) | (3,3) | (4,3) | (5,3) | (6,3) | 0 |
0 | (1,2) | (2,2) | (3,2) | (4,2) | (5,2) | (6,2) | 0 | 0 |
(1,1) | (2,1) | (3,1) | (4,1) | (5,1) | (6,1) | 0 | 0 | 0 |
dp时注意除了(1,1)和(m,n)其余的要判断是否是同一个点,若是则忽略,不是则转移状态。
Code:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 110;
int map[maxn][maxn], f[maxn][maxn][maxn], n, m;
inline void read(int &a) {
int f = 1;
char ch = getchar();
a = 0;
while(ch < '0' || ch > '9') {
if(ch == '-') f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
a = a*10 + ch - 48;
ch = getchar();
}
a *= f;
}
inline void write(int a) {
int top = 0;
char ch[30];
if(a < 0) { putchar('-'); a = -a; }
do {
ch[top++] = a%10 + 48;
a /= 10;
} while(a);
while(top--) putchar(ch[top]);
putchar('\n');
}
inline void init() {
read(m); read(n);
for(int i = 1; i <= m; ++i) for(int j = 1; j <= n; ++j)
read(map[i+j-1][i]);
}
inline void work() {
for(int k = 1; k < m + n; ++k)
for(int i = 1; i < m + n; ++i) for(int j = 1; j < m + n; ++j) {
if((i != j && k != m + n - 1) || (i == j && k == m + n - 1)) {
f[k][i][j] = max(max(f[k-1][i-1][j-1], f[k-1][i-1][j]), max(f[k-1][i][j-1], f[k-1][i][j]));
f[k][i][j] += map[k][i] + map[k][j];
}
}
write(f[m+n-1][m][m]);//这里的点的顺序是右上到左下,所以(m,n)是第m+n-1条斜线上的第m个格子
}
int main() {
init();
work();
return 0;
}