题目链接:
https://www.luogu.org/problem/P1006
题意:
一个n*m的网格,每个格子有一个值,要求从左上(1,1)找到两条到右下(m,n)不重合的路径且两条路径上格子的值的和最大,每次移动只能向下或向右(0<=m,n<=50),起点(1,1)和终点(m,n)的值为0。
题解:
显然可以用四维dp(当然有些机智的巨佬发现可以用三维dp),一条路径走到(i,j),另一条走到(k,t),因为不能重合,所以第四重循环的t要从j+1开始,因为第一条路径走到(i,j)时,以(1,1),(1,j),(i,1),(i,j)为顶点的矩形内的点都已被第一条路径走过,而且以(1,1),(1,n),(i,1),(i,n)为顶点的矩形内还未走的点将被第一条路径走过。
状态转移方程:
dp[i][j][k][t]=max(dp[i-1][j][k-1][t]+a[i][j]+a[k][t],dp[i-1][j][k][t-1]+a[i][j]+a[k][t],dp[i][j-1][k-1][t]+a[i][j]+a[k][t],dp[i][j-1][k][t-1]+a[i][j]+a[k][t])
代码:
#include <iostream>
#include <cstdlib>
#include <algorithm>
using namespace std
;
int dp
[55][55][55][55];
int s
[55][55];
int main()
{
int m
,n
;
int a
[55][55];
cin
>>n
>>m
;
for(int i
=1;i
<=n
;i
++)
{
for(int j
=1;j
<=m
;j
++) cin
>>a
[i
][j
];
}
for(int i
=1;i
<=n
;i
++)
{
for(int j
=1;j
<=m
;j
++)
{
for(int k
=1;k
<=n
;k
++)
{
for(int t
=j
+1;t
<=m
;t
++)
dp
[i
][j
][k
][t
]=max(dp
[i
-1][j
][k
-1][t
]+a
[i
][j
]+a
[k
][t
],max(dp
[i
-1][j
][k
][t
-1]+a
[i
][j
]+a
[k
][t
],max(dp
[i
][j
-1][k
-1][t
]+a
[i
][j
]+a
[k
][t
],dp
[i
][j
-1][k
][t
-1]+a
[i
][j
]+a
[k
][t
])));
}
}
}
cout
<<dp
[n
][m
-1][n
-1][m
];
return 0;
}