【NOIP2000】T4方格取数
来源:互联网 发布:知乎周刊第一本 编辑:程序博客网 时间:2024/05/17 07:16
//////////////////////////////////////////////////////////
设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示(见样例):
某人从图的左上角的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
67
////////////////////////////////////////////////////////////////////////////////////
题目直接限制了只能向下或向右走,换句话说就是每个点只能由上或由左走到。因此,如果只考虑一条路径,还是比较直观就能想明白:
则F[i][j]=max{F[i-1][j],F[i][j-1]} +a[i][j]//F[i][j]只能由这两格转移来
for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(f[i-1][j]>f[i][j-1])f[i][j]=f[i-1][j]+map[i][j]; else f[i][j]=f[i][j-1]+map[i][j];
虽然,题目要求又多了一条路径,但是如果沿着这个思路,也就不难想了,只是需要四维数组,分别记下两条路径。而下一个状态,应该是以四种状态中的最大值转移得来。由于题目限制n<=10,于是就可以不用犹豫使用这样的四种循环动规求解了,列出动态转移方程:
则F[i][j][k][l]=max{F[i-1][j][k-1][l],F[i][j-1][k-1][l],F[i-1][j][k][l-1],F[i][j-1][k][l-1]}+a[i][j]+a[k][l]
//分别是第一条路径的两种和第二条路径的两种,乘法原理
for(i=1;i<=n;i++) for(j=1;j<=n;j++) for(k=1;k<=n;k++) for(l=1;l<=n;l++){ f[i][j][k][l]=max(f[i-1][j][k-1][l],f[i][j-1][k-1][l], f[i-1][j][k][l-1],f[i][j-1][k][l-1])+map[i][j]+map[k][l]; if(i==k&&j==l)f[i][j][k][l]-=map[i][j]; }
这里还有一个容易忽视的细节,i,j,k,l重合时,a[i][j]只能被加一次//边界条件
这题尽管不是很难理解,但利用了n<=10这一条件,用四维数组DP的做法还是很巧妙。
////////////////////////////////////////////////////////////////////////////////////
居然还有四维压三维的做法
之前的F[i][j][k][l]四维做法,会发现有许多冗余计算:对于每一组路径上各取一点的所有组合都会被重复计算。
我们可以发现因为只能向下或向右,两条路径的长度是确定的,而设共走了k步(以左上角为第一步),对于每一个k,点(i,j)的坐标都有i=k-j+1,因此就可以以一个k代替原来的两个横坐标(或纵坐标)。
于是可以进行三维的优化:
设F[i][j][k]表示第一条路径走到第i列,第二条路径走到第j列,共走了k步时的最大值
这样,动态转移方程就是:
F[i][j][k]=max(F[i-1][j][k-1],F[i][j-1][k-1],F[i][j][k-1],F[i-1][j-1][k-1])+a[i][k-i+1]+a[j][k-j+1]
//F[i][j][k]由上一步k-1的四个点的最大值转移,四个点与四维做法相同
还有一点是,由于记录的是步数,对应步数下的i,j取值范围改变,应为[1,k](k<=n),[k-n+1,n](k>n)
所以,最后的代码O(n^3):
f[1][1][1]=map[1][1];for(k=2;k<=2*n-1;k++) for(i=max(1,k-n+1);i<=min(n,k);i++) for(j=max(1,k-n+1);j<=min(n,k);j++){ f[i][j][k]=max(max(f[i-1][j][k-1],f[i][j-1][k-1]), max(f[i][j][k-1],f[i-1][j-1][k-1]))+map[i][k-i+1]+map[j][k-j+1]; if(i==j)f[i][j][k]-=map[i][k-i+1]; }printf("%d",f[n][n][2*n-1]);
这就很妙了( ̄▽ ̄)~*
- noip2000 方格取数 T4
- 【NOIP2000】T4方格取数
- 洛谷 P1004 [NOIP2000 T4] 方格取数
- Noip2000方格取数
- NOIP2000方格取数
- NOIP2000 方格取数
- NOIP2000 方格取数
- NOIp2000 方格取数
- 【NOIP2000】方格取数
- #NOIP2000#方格取数
- 【NOIP2000】方格取数
- 【NOIP2000】方格取数
- NOIP2000 方格取数
- 【DP】[NOIP2000]方格取数
- noip2000 方格取数 (动态规划)
- [NOIP2000] 方格取数-解题报告
- P1004 方格取数题解NOIP2000
- noip2000 方格取数(多重DP)
- 7.笔记 MySQL学习——向表中添加行
- 点击Echarts饼图生成动态Table
- 产品可靠性测试用例1
- C++:复数相加
- 软件工程(C编码实践篇)学习总结
- 【NOIP2000】T4方格取数
- 一看就明白的爬虫入门讲解:基础理论篇
- C语言-函数实现模块化设计-函数的递归调用
- react-native 打包遇到aapt错误解决方案
- 轻量级插件myFocus的使用
- Http请求的状态码说明
- java中如何输入char类型
- C++:汉诺塔问题
- 自学网络结构(二):Learning Transferable Architectures for Scalable Image Recognition