NYOJ 传纸条(一) 双向dp

刚开始的想法是跑两遍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;
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值