P1006 传纸条
刚开始想的是两次01背包,把第一次走过的给记录下来。好像不太好记录,
参考了大佬的博客,数据范围不是很大,四维数组就可以了,
a,b第一个人走的,c,d代表第二个人
dp[a][b][c][d] = max{dp[a][b -1][c][d -1] , dp[a - 1][b][c -1][d],
dp[a][b -1][c -1][d],dp[a - 1][b][c][d -1]}+a[a][b] + a[c][d];
只要保证纵坐标不一样就行,d = b + 1开始循环
最后输出是dp[n][m - 1][n - 1][m];
第一个人到第二个人只能往右或者往下走,所以到达的点是n,m-1
同理,第二个人到达的点是n-1,m;
如果卡的厉害,可以变为三维数组,怎么操作呢?
每次转移的时候,两个人走的步数是相等的,
枚举横坐标
k表示总的步数,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 int a[55][55],dp[110][55][55]; 5 int n,m; 6 7 int main(){ 8 //freopen("in","r",stdin); 9 ios::sync_with_stdio(0); 10 cin >> n >> m; 11 for(int i = 1; i <= n; i++){ 12 for(int j = 1; j <= m; j++){ 13 cin >> a[i][j]; 14 } 15 } 16 for(int k = 1; k <= n + m - 1; k++){ 17 for(int i = 1; i <= n; i++){ 18 for(int j = 1; j <= n; j++){ 19 if(k - i < 0 || k - j < 0) 20 continue; 21 dp[k][i][j] = max(max(dp[k - 1][i][j],dp[k - 1][i - 1][j - 1]),max(dp[k - 1][i][j - 1],dp[k - 1][i - 1][j])) + a[i][k - i + 1] + a[j][k - j + 1]; 22 if(i == j) 23 dp[k][i][j] -= a[i][k - i + 1]; 24 } 25 } 26 } 27 cout << dp[n + m - 1][n][n] << endl; 28 return 0; 29 }