DP
题目链接:https://www.luogu.org/problem/show?pid=1004
题目大意:
给你一个矩阵,有一些点上有数字,只能向右走或向下走,走过后这个点上的数字会变成0,从左上角到右下角走两次,所能得到的最大数字之和
A:如果不考虑走两次的话,会简单一点,那首先设计状态~
B:f[ i ][ j ] 表示从起点到 i,j 点 所能取得的数字和最大为f[ i ][ j ]
A:然后想想对于每个点他能由哪里直接推出来?
B:因为只能向右或向下,所以他一定是由左边或者上边走过来
A:走过来就加上这个点的数字?
A:然后:
f[i][j] = max(f[i - 1][j],f[i][j - 1]) + mp[i][j];
是这样么??
B:因为要走两遍,所以跑两次,然后第一次走过的都设成0不就可以了?
A:等等等等,两次的最优真的等同于一次同时考虑两个的最优么??(哈哈哈嗝,就是不告诉你答案~~)
(解释见下文)
END.
对于每一个点,都可以由左边或上边走过来
因为要走两遍所以可以看成是两个同时从左上角开始走
这样的话这样才能确定一种状态呢?
你需要同时知道两个点的坐标,是同时!!
设计状态:f[i][j][a][b] 为第一个点走到i,j 第二个点走到a,b时所能取到的最大数字和
(有5个量,把其中4个确定,另一个作为答案统计)
根据移动的规则,很容易就能推出方程来啦~
f[i][j][a][b] = maxx(f[i - 1][j][a - 1][b],f[i - 1][j][a][b - 1],
f[i][j - 1][a][b - 1],f[i][j - 1][a - 1][b]);
那怎么处理走过的情况呢?
因为只能向右走或向下走,
所以a路走到b路已走过的点时,
b路一定也在正这个点上,
也就是说,
他们一定是同时走到相同的点。(自己动手试试啦~)
那我们可以直接判两点是否是同一个点来判断是否走重。
好的,现在该注意的都分析了,
然后。。。贴代码??
当然不是不是不是!!
还记得小A的问题么(A:记得记得!)
为什么不能看成是两次最优的组合呢?
那是因为在同时考虑两条路时,不仅考虑了一条最优,
还考虑了在这条最优的路线之外还能尽量多的走过多少数字,
而在考虑一条路时,可能会导致本来可以全取走的数没能取完。
看数据看数据:
样例输入:
7
1 3 2
1 4 3
2 3 3
3 3 3
5 5 4
6 5 4
7 3 2
7 5 4
0 0 0
二维DP输出:23
四维DP输出:25
方格示意图:
0 0 2 3 0 0 0
0 0 3 0 0 0 0
0 0 3 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 4 0 0
0 0 0 0 5 0 0
0 0 2 0 4 0 0
嗯,这个题就是这样了
Codes:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 10 + 5;
int n,mp[N][N];
int f[N][N][N][N],bo[N][N];
int maxx(int x,int y){
if(x > y) return x;
return y;
}
int main(){
scanf("%d",&n);
int a,b,c;
for(;;){
scanf("%d%d%d",&a,&b,&c);
if(a == b && b == c && c == 0)
break;
mp[a][b] = c;
}
for(int i = 1;i <= n;++ i){
for(int j = 1;j <= n;++ j){
for(int a = 1;a <= n;++ a){
for(int b = 1;b <= n;++ b){
f[i][j][a][b] = maxx(f[i - 1][j][a - 1][b],f[i - 1][j][a][b - 1]);
f[i][j][a][b] = maxx(f[i][j][a][b],f[i][j - 1][a][b - 1]);
f[i][j][a][b] = maxx(f[i][j][a][b],f[i][j - 1][a - 1][b]);
if(i == a && j == b)
f[i][j][a][b] += mp[i][j];
else f[i][j][a][b] += mp[i][j] + mp[a][b];
/* else if(!bo[i][j] || !bo[a][b]){ //之前的错误判法
if(!bo[i][j]){
f[i][j][a][b] += mp[i][j];
}
if(!bo[a][b]){
f[i][j][a][b] += mp[a][b];
}
bo[i][j] = bo[a][b] = 1;
}*/
// cout << f[i][j][a][b] << '
';
}
}
}
}
cout << f[n][n][n][n] << '
';
return 0;
}
MAS:
考虑思路的正确性?(好吧这很重要)
不会写就加维度?