原题链接
题目大意
有两个人在传纸条,一个人在坐标 ( 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(fi1−1,j1,i2−1,j2,fi1−1,j1,i2,j2−1,fi1,j1−1,i2−1,j2,fi1,j1−1,i2,j2−1)+ai,j+ai2,j2 i1=i2 or j1=j2max(fi1−1,j1,i2−1,j2,fi1−1,j1,i2,j2−1,fi1,j1−1,i2−1,j2,fi1,j1−1,i2,j2−1)+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