题目大意
给出一个地图,从左上角往右下角走两次,只能往下和右走,每次经过一个有值的点就会取走方格中的数(获得数且使当前方格变为0),求走两次最大的取得数之和。
解题思路
刚看到这题第一个想到的就是贪心,但是由于要走两次,所以无法保证两次的结果之和为最优,所以不能用贪心。
由于只能往右和下走,所以具有无后效性,因此可以用dp,只不过需要同时dp两条路。定义数组
f
f
f,
f
i
1
,
j
1
,
i
2
,
j
2
f_{i1},_{j1},_{i2},_{j2}
fi1,j1,i2,j2表示当第一次走到i1,j1,第二次走到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
(感谢wtj提供的格式)
代码
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n,m,f[15][15][15][15],a[100][100];
int main()
{
cin>>n>>m;
int x,y,z;
while(1){
cin>>x>>y>>z;
a[x][y]=z;
if(!x&&!y&&!z) break;
}
for(int i1=1;i1<=n;i1++)
for(int j1=1;j1<=n;j1++)//枚举第一条路位置
for(int i2=1;i2<=n;i2++)
for(int j2=1;j2<=n;j2++)//枚举第二条路位置
{
int p=max(f[i1-1][j1][i2-1][j2],max(f[i1-1][j1][i2][j2-1],max(f[i1][j1-1][i2-1][j2],f[i1][j1-1][i2][j2-1])));//上一步所取得的最大值
if(i1==i2&&j1==j2) f[i1][j1][i2][j2]=p+a[i2][j2];
else f[i1][j1][i2][j2]=p+a[i1][j1]+a[i2][j2];//如果走到了同一个位置就只加一个
}
cout<<f[n][n][n][n];
return 0;
}