NYOJ 传纸条(一) 双向dp

来源:互联网 发布:淘宝回收十字绣靠谱吗 编辑:程序博客网 时间:2024/05/02 02:40

刚开始的想法是跑两遍dp  第一次找权值最大的路径  然后把走过的路径标记为负无穷大  然后在走一遍就好了  但是后来发现如果要让两次的和最大  那么第一次的路线可能不是最大的一条路  所以并不能这么写   看了别人的题解  题解我都看了两天 真是有意思


思路是这样的  我们假设有两个小人从左上角走到右下角  不同路线走 不相交  就代替了这个模型  用一个dp[i][j][k] 来表示当走了I步时其中一个人的x坐标为j另一个人的x坐标为k

不难想到当前状态可以来自四种其他状态  分别是小人一号来自左边 小人二号来自上边 或者小人一号来自左边小人二号来自左边 或者小人一号来自上边小人二号来自左边 或者小人一号来自上边小人二号来自上边  就这样  转移方程是 :dp[i][j][k] = max(max(dp[I - 1][j][k], dp[I - 1][j - 1][k]), max(dp[I - 1][j - 1][k - 1], dp[I - 1][j][k - 1]));


我写这道题的时候把储存权值的表定义成了char类型 然后debug一早上 真是醉了

参考了这个人的博客 写的很详细

点击打开链接


#include <iostream>#include <algorithm>#include <cstring>using namespace std;int dp[110][55][55];int main(){int t, n, m;int  str[55][55];cin >> t ;while ( t -- ) {cin >> n >> m ;for (int i = 1;i <= n; i ++) for (int j = 1; j <= m; j ++)cin >> str[i][j] ;memset(dp , 0, sizeof(dp));for (int i = 1; i < m + n ; i ++) {for (int j = 1; j <= min(n , i); j ++) {int y1 = i - j + 1;if(y1 > m)continue;for (int k = j +1; k <=min(i , n); k ++) {int y2 = i - k + 1;int temp = -1;temp = max(temp , dp[i - 1][j - 1][k - 1]);temp = max(temp , dp[i - 1][j - 1][k]);temp = max(temp , dp[i - 1][j][k - 1]);temp = max(temp , dp[i - 1][j][k]);dp[i][j][k] = temp + str[j][y1] + str[k][y2];}}}int ans = 0;ans = max (ans , dp[m + n - 2][n - 1][n]);ans = max (ans , dp[m + n - 2][n][n - 1]);cout << ans << endl;}}

原创粉丝点击