今天我们来练习一道有关动态规划的题--方格取数。
设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放
人数字0。如下图所示(见样例):
A
0 0 0 0 0 0 0 0
0 0 13 0 0 6 0 0
0 0 0 0 7 0 0 0
0 0 0 14 0 0 0 0
0 21 0 0 0 4 0 0
0 0 15 0 0 0 0 0
0 14 0 0 0 0 0 0
0 0 0 0 0 0 0 0
. B
某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角的B
点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
此人从A点到B点共走两次,试找出2条这样的路径,使得取得的数之和为最大。
输入格式:
输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个
表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。
输出格式:
只需输出一个整数,表示2条路径上取得的最大的和。
样例:
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0
看到这张矩阵图许多人肯定先会想到搜索,dfs,bfs之类的,可是这会涉及一个时间长短的问题。如果样例范围过大,用dfs就定会超时(加了记忆化也基本上没什么大的作用
自古许多NOIP大佬说过:骗分过样例,暴力出奇迹,暴搜挂着机,打表出省一。
看到这题目描述:两条路径和的最大值,我们想一想:我们可不可以一起搜,而非搜完一条路再删掉再搜,这样会节约许多时间。我们可以枚举它的坐标,设x1,y1,x2,y2分别为第一、二条路线的横、纵坐标,然后每一次累加该方格的值,打个擂台,来进行最优决策。所以这道题可以用暴力求解的方法。
那么我们的每一次的值来源于哪里呢?其实我们并不需要去记录每一条路线,而是在矩阵中调出可以到该点的另外两个点的横纵坐标。我们用一张图即可发现规律:
总的来说,每走一步都会有四个分支(你理解成选择或者情况也可以):
1、两种都向下走
2、第一种向下走,第二种向右走
3、第一种向右走,第二种向下走
4、两种都向右走
可是,事情往往没有那么一帆风顺,我们假设,如果两条路径重合了,或有共同交点了,那该怎么办?因为我们是求和,所以如果到了一个相同的点,那我们的值不可以累加两次,所以还得加一个特判,来减去多余加上的值。
代码如下请勿抄袭:
1 #include <stdio.h>
2 #include <algorithm>
3 using namespace std;
4 int n,x,y,v,dp[101][101][101][101],a[101][101];
5 int main()
6 {
7 scanf("%d",&n);
8 while(1)//输入
9 {
10 scanf("%d %d %d",&x,&y,&v);
11 if(!x) break;
12 else a[x][y]=v;
13 }
14 for(int x1=1;x1<=n;x1++)
15 for(int y1=1;y1<=n;y1++)
16 for(int x2=1;x2<=n;x2++)
17 for(int y2=1;y2<=n;y2++)//4个循环来枚举两条路在矩阵中的位置
18 {
19 dp[x1][y1][x2][y2]=max(max(dp[x1-1][y1][x2-1][y2],dp[x1-1][y1][x2][y2-1]),max(dp[x1][y1-1][x2-1][y2],dp[x1][y1-1][x2][y2-1]))+a[x1][y1]+a[x2][y2];//状态转移方程
20 if(x1==x2&&y1==y2) dp[x1][y1][x2][y2]-=a[x1][y1];//减去重复的值
21 }
22 printf("%d",dp[n][n][n][n]);//输出最优解
23 return 0;
24 }
我们还可以发现,当两条路同时走的时候,总是在棋盘的一根对角线上,我们可以用它,找出点的关系,就可以实现把四维转换为三维,可以尝试。
ps:感觉动态规划越来越难了。。。。听说明天还会讲树形dp。。。加油吧!
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。