P1006 传纸条
题目大意:
给一个带权矩阵,从 ( 1 , 1 ) (1,1) (1,1) 走到 $(n, m) $,可以向下或向右走,选两条不相交的路,问两条路的最大权值是多少。
思路:
直接定义数组 d p [ i ] [ j ] [ x ] [ y ] dp[i][j][x][y] dp[i][j][x][y], 表示当前第一条路走到 ( i , j ) (i, j) (i,j) 第二条路走到 ( x , y ) (x, y) (x,y) 的答案,两条路一定要同时走,意思就是第一条路走了多少步,第二条路也得走多少步,那么很明显就由一个等式 i + j = x + y i+j=x+y i+j=x+y,所以我们可以直接枚举 i , j , x i, j, x i,j,x , y = i + j − x y = i + j - x y=i+j−x
状态转移方程就是
$
dp[i][j][x][y] = max(dp[i-1][j][x-1][y], dp[i-1][j][x][y-1],dp[i][j-1][x-1][y], dp[i][j-1][x][y-1]) + num[i][j] + num[x][y]
$
如果两个点走到一起,那就要减去一份权值。
会发现 y y y 的状态是由其他状态决定的,所以最后一维也可以省去
代码:
#include <bits/stdc++.h>
using namespace std;
#define me(a, b) memset(a, b, sizeof(a))
#define IOS() ios::sync_with_stdio(false), cin.tie(0)
#define endl '\n'
typedef long long ll;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int maxn = 50 + 5;
const ll mod = 1e9 + 7;
int num[maxn][maxn];
int dp[maxn][maxn][maxn];
int main()
{
IOS();
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j)
cin >> num[i][j];
}
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
for(int x = 1; x <= n; ++x) {
int y = i + j - x;
if(y <= 0) continue;
dp[i][j][x] = max(
max(dp[i-1][j][x-1], dp[i-1][j][x]),
max(dp[i][j-1][x-1], dp[i][j-1][x])
) + num[i][j] + num[x][y];
if(i == x && j == y)
dp[i][j][x] -= num [i][j];
}
}
}
cout << dp[n][m][n] << endl;
return 0;
}
总结:
这题以前没做出,当时看了题解,现在依然没做出,学了就忘哎