SSL 1589 P1006 传纸条

题目描述:

题目传送门


解题思路:

诸如此类无后效性找路的问题,我们可以考虑DP。

理解题目,求出从 ( 1 , 1 ) (1,1) (1,1) ( n , m ) (n,m) (n,m),走两次,走过的数会变为0,求一个最大值。
很容易想到是先从 ( 1 , 1 ) (1,1) (1,1) 走一次DP到 ( n , m ) (n,m) (n,m) 求最长路径,然后修改走过的点变为0,然后再DP一遍,把前后两趟DP的结果加起来,求出答案。

这是一种很自然的想法,这种解法确实能过样例,但举出反例也不难如图:
在这里插入图片描述
图二为走第一次 DP 时的走法。但我们发现,如果按照图二这么走,那么当我们走第二趟时就必然要舍弃 2 2 2 或者 3 3 3 。但如果我们按照图三这样走第一遍的话,那么我们可以一个不漏的照顾到地图上的全部数字,两者的优劣性可想而知。

因此,这道题成为了多进程的最优化决策问题。

不难发现,要使答案最优,我们需要让走的路径互相配合,因此考虑两条路径同时进行 DP 。
f i 1 , j 1 , i 2 , j 2 f_{i1,j1,i2,j2} fi1,j1,i2,j2 表示从 ( 1 , 1 ) (1,1) (1,1) 走到 ( i 1 , j 1 ) (i1,j1) (i1,j1) 以及 ( i 2 , j 2 ) (i2,j2) (i2,j2) 时的最长路径的和,
f i 1 , j 1 , i 2 , j 2 f_{i1,j1,i2,j2} fi1,j1,i2,j2 可以从 f i 1 − 1 , j 1 , i 2 , j 2 − 1 f_{i1-1,j1,i2,j2-1} fi11,j1,i2,j21 f i 1 , j 1 − 1 , i 2 − 1 , j 2 f_{i1,j1-1,i2-1,j2} fi1,j11,i21,j2 f i 1 , j 1 − 1 , i 2 , j 2 − 1 f_{i1,j1-1,i2,j2-1} fi1,j11,i2,j21 f i 1 − 1 , j 1 , i 2 − 1 , j 2 f_{i1-1,j1,i2-1,j2} fi11,j1,i21,j2 ,四个位置进行转移。

因此,我们推出状态转移方程:

f i 1 , j 1 , i 2 , j 2 = { m a x ( f i 1 − 1 , j 1 , i 2 , j 2 − 1 , f i 1 , j 1 − 1 , i 2 − 1 , j 2 , f i 1 , j 1 − 1 , i 2 , j 2 − 1 , f i 1 − 1 , j 1 , i 2 − 1 , j 2 ) + a i 1 , j 1 i 1 = i 2 ∧ j 1 = j 2 m a x ( f i 1 − 1 , j 1 , i 2 , j 2 − 1 , f i 1 , j 1 − 1 , i 2 − 1 , j 2 , f i 1 , j 1 − 1 , i 2 , j 2 − 1 , f i 1 − 1 , j 1 , i 2 − 1 , j 2 ) + a i 1 , j 1 + a i 2 , j 2 otherwise f_{i1,j1,i2,j2}=\begin{cases} max(f_{i1-1,j1,i2,j2-1} , f_{i1,j1-1,i2-1,j2},f_{i1,j1-1,i2,j2-1},f_{i1-1,j1,i2-1,j2})+a_{i1,j1}&i1=i2\land j1=j2\\ max(f_{i1-1,j1,i2,j2-1} , f_{i1,j1-1,i2-1,j2},f_{i1,j1-1,i2,j2-1},f_{i1-1,j1,i2-1,j2})+a_{i1,j1}+a_{i2,j2}&\text{otherwise} \end{cases} fi1,j1,i2,j2={max(fi11,j1,i2,j21,fi1,j11,i21,j2,fi1,j11,i2,j21,fi11,j1,i21,j2)+ai1,j1max(fi11,j1,i2,j21,fi1,j11,i21,j2,fi1,j11,i2,j21,fi11,j1,i21,j2)+ai1,j1+ai2,j2i1=i2j1=j2otherwise


CODE:

#include <iostream>
using namespace std;
long long n,m,a[60][60]={0};
long long f[60][60][60][60]={0};
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=m;j++)
	    cin>>a[i][j];
	for(int i1=1;i1<=n;i1++)
	  {
	  	for(int j1=1;j1<=m;j1++)
	  	  {
	  	  	for(int i2=1;i2<=n;i2++)
	  	  	  {
	  	  	  	for(int j2=1;j2<=m;j2++)
	  	  	  	  {
	  	  	  	  	int p=max(max(f[i1-1][j1][i2][j2-1],f[i1][j1-1][i2-1][j2]),max(f[i1-1][j1][i2-1][j2],f[i1][j1-1][i2][j2-1]));
	  	  	  	  	if(i1==i2&&j1==j2) f[i1][j1][i2][j2]=p+a[i1][j1];
	  	  	  	  	if(i1!=i2||j1!=j2) f[i1][j1][i2][j2]=p+a[i1][j1]+a[i2][j2];
				  }
			  }
		  }
	  }
	cout<<f[n][m][n][m];
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值