P1006 传纸条

原题链接

P1006 传纸条

题目大意

有两个人在传纸条,一个人在坐标 ( 1 , 1 ) (1,1) (1,1) 处,一个人在坐标 ( n , m ) (n,m) (n,m) 处。纸条需要从 ( 1 , 1 ) (1,1) (1,1) 处传到 ( n , m ) (n,m) (n,m) 处(只能向下或向右传),再从 ( n , m ) (n,m) (n,m)处传到 ( 1 , 1 ) (1,1) (1,1) 处(只能向上或向左传),在每一个位置上的同学都对应一个好心程度,他们希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度之和最大。

解题思路

使用贪心算法一定是不行的,我们需要考虑动态规划。如何规划?最好想的办法,就是走两次最优路径,第一次走完之后,就把路径清除掉。但是,这个做法是不行的,举个例子:传纸条
图一是题目所给出的表,图二是按照最优路径走一次的方法。不难发现,如果按照最优路径走一遍,走两次的和并不是最大的(因为第二次不可能两个位置都取到),而第一次如果按照图三来走,两次就可以将所有的位置的数字都经过。
看来得要换一种方法进行动态规划。因为是否最优,与两个纸条都有关系,所以我们可以考虑使用 f i 1 , j 1 , i 2 , j 2 f_{i1,j1,i2,j2} fi1,j1,i2,j2 表示一张纸条在 ( 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 = { 0                                                                                                           i 1 = 0   o r   j 1 = 0   o r   i 2 = 0   o r   j 2 = 0 m a x ( f i 1 − 1 , j 1 , i 2 − 1 , j 2 , 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 ) + a i , j + a i 2 , j 2            i 1 ≠ i 2   o r   j 1 ≠ j 2 m a x ( f i 1 − 1 , j 1 , i 2 − 1 , j 2 , 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 ) + a i , j                      i 1 = i 2   a n d   j 1 = j 2 f_{i1,j1,i2,j2}=\left\{\begin{matrix}0 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i1=0\ or\ j1=0\ or\ i2=0\ or\ j2=0 \\max(f_{i1-1,j1,i2-1,j2},f_{i1-1,j1,i2,j2-1},f_{i1,j1-1,i2-1,j2},f_{i1,j1-1,i2,j2-1})+a_{i,j}+a_{i2,j2}\ \ \ \ \ \ \ \ \ \ i1\ne i2\ or\ j1\ne j2 \\max(f_{i1-1,j1,i2-1,j2},f_{i1-1,j1,i2,j2-1},f_{i1,j1-1,i2-1,j2},f_{i1,j1-1,i2,j2-1})+a_{i,j}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i1=i2\ and\ j1=j2\end{matrix}\right. fi1,j1,i2,j2=0                                                                                                         i1=0 or j1=0 or i2=0 or j2=0max(fi11,j1,i21,j2,fi11,j1,i2,j21,fi1,j11,i21,j2,fi1,j11,i2,j21)+ai,j+ai2,j2          i1=i2 or j1=j2max(fi11,j1,i21,j2,fi11,j1,i2,j21,fi1,j11,i21,j2,fi1,j11,i2,j21)+ai,j                    i1=i2 and j1=j2
但是题目要求纸条需要从 ( 1 , 1 ) (1,1) (1,1) 处传到 ( n , m ) (n,m) (n,m) 处(只能向下或向右传),再从 ( n , m ) (n,m) (n,m)处传到 ( 1 , 1 ) (1,1) (1,1) 处(只能向上或向左传),这样两个纸条都只是满足第一个要求,第二个怎么办?其实,这样已经可以AC了,因为这样其实,也满足了第二个要求,本质上,两者是一样的,所以只要开通两条满足第一个要求的路径就好了。

代码实现

#include<iostream>
#include<cmath>
using namespace std;
int n,m,a[60][60],f[60][60][60][60];
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 i=1;i<=n;i++){//枚举位置
		for(int j=1;j<=m;j++){//枚举位置
			for(int i2=1;i2<=n;i2++){//枚举位置
				for(int j2=1;j2<=m;j2++){//枚举位置
					f[i][j][i2][j2]=max(max(f[i-1][j][i2-1][j2],f[i][j-1][i2-1][j2]),max(f[i-1][j][i2][j2-1],f[i][j-1][i2][j2-1]))+a[i][j];//转移方程
					if(i!=i2||j!=j2)
						f[i][j][i2][j2]+=a[i2][j2];//转移方程
				}
			}
		}
	}
	cout<<f[n][m][n][m];
}

样例

输入

3 3
0 3 9
2 8 5
5 7 0

输出

 34
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值