51nod 1084 更难的矩阵取数问题(DP)
2015-10-04 22:06
274 查看
原题链接:点击打开链接
一个M*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,先从左上走到右下,再从右下走到左上。第1遍时只能向下和向右走,第2遍时只能向上和向左走。两次如果经过同一个格子,则该格子的奖励只计算一次,求能够获得的最大价值。
例如:3 * 3的方格。
1 3 3
2 1 3
2 2 1
能够获得的最大价值为:17。1 -> 3 -> 3 -> 3 -> 1 -> 2 -> 2 -> 2 -> 1。其中起点和终点的奖励只计算1次。
输入
输出
输入示例
输出示例
比较容易想到的是直接进行两次类似数塔问题的DP。实际上,这个解法是有问题的。
比如:
5 5
10 1 1 1 1
10 1 1 1 1
10 10 10 1 10
1 1 1 1 1
10 1 10 10 10
其实,可以将两次取数看作两个人同时从左上角出发(只能向右/向下走),由此设出状态:
dp[x1][y1][x2][y2]表示第一个人走到(x1,y1),第二个人走到(x2,y2)时的最大价值。
那么有:dp[x1][y1][x2][y2]=max(dp[x1'][y1'][x2'][y2'])+M[x1][y1]+M[x2][y2]。 (x1',y1'为向右或向左走一步能够到达x1、y1的格子)
时间和空间复杂度均为O(n^2*m^2)
优化:
发现两人每走一步都有:x1+y1=x2+y2=当前走的步数
如果知道走的步数,只要知道某人的横坐标即可推算出其纵坐标。因此设dp[i][j][k]表示两人走i步,第一个人到达第i行,第二个人到达第k行时的最大价值。
dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-1][k],dp[i-1][j][k-1],dp[i-1][j-1][k-1])+M[x1][y1]+M[x2][y2] (x1!=x2)
时间和空间复杂度优化到O((n+m)*n^2)
注意到,状态转移方程中dp[i][j][k]的状态只与前一步的状态有关,因此空间复杂度还可以优化到O(n^2)
上面的状态转移方程为x1!=x2时的,由于当两人走过同一个格子时,该格子价值只算一次,因此当x1=x2时,加上M[x1][y1]即可。
一个M*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,先从左上走到右下,再从右下走到左上。第1遍时只能向下和向右走,第2遍时只能向上和向左走。两次如果经过同一个格子,则该格子的奖励只计算一次,求能够获得的最大价值。
例如:3 * 3的方格。
1 3 3
2 1 3
2 2 1
能够获得的最大价值为:17。1 -> 3 -> 3 -> 3 -> 1 -> 2 -> 2 -> 2 -> 1。其中起点和终点的奖励只计算1次。
输入
第1行:2个数M N,中间用空格分隔,为矩阵的大小。(2 <= M, N <= 200) 第2 - N + 1行:每行M个数,中间用空格隔开,对应格子中奖励的价值。(1 <= A[i,j] <= 10000)
输出
输出能够获得的最大价值。
输入示例
3 3 1 3 3 2 1 3 2 2 1
输出示例
17
比较容易想到的是直接进行两次类似数塔问题的DP。实际上,这个解法是有问题的。
比如:
5 5
10 1 1 1 1
10 1 1 1 1
10 10 10 1 10
1 1 1 1 1
10 1 10 10 10
其实,可以将两次取数看作两个人同时从左上角出发(只能向右/向下走),由此设出状态:
dp[x1][y1][x2][y2]表示第一个人走到(x1,y1),第二个人走到(x2,y2)时的最大价值。
那么有:dp[x1][y1][x2][y2]=max(dp[x1'][y1'][x2'][y2'])+M[x1][y1]+M[x2][y2]。 (x1',y1'为向右或向左走一步能够到达x1、y1的格子)
时间和空间复杂度均为O(n^2*m^2)
优化:
发现两人每走一步都有:x1+y1=x2+y2=当前走的步数
如果知道走的步数,只要知道某人的横坐标即可推算出其纵坐标。因此设dp[i][j][k]表示两人走i步,第一个人到达第i行,第二个人到达第k行时的最大价值。
dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-1][k],dp[i-1][j][k-1],dp[i-1][j-1][k-1])+M[x1][y1]+M[x2][y2] (x1!=x2)
时间和空间复杂度优化到O((n+m)*n^2)
注意到,状态转移方程中dp[i][j][k]的状态只与前一步的状态有关,因此空间复杂度还可以优化到O(n^2)
上面的状态转移方程为x1!=x2时的,由于当两人走过同一个格子时,该格子价值只算一次,因此当x1=x2时,加上M[x1][y1]即可。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define inf 0x3f3f3f3f #define maxn 201 int M[maxn][maxn]; int dp[maxn<<1][maxn][maxn]; int main() { int n,m,i,j,x1,x2; scanf("%d%d",&m,&n); for(i=0;i<n;++i) for(j=0;j<m;++j) scanf("%d",&M[i][j]); memset(dp,0,sizeof(dp)); dp[0][0][0]=M[0][0]; for(i=1;i<n+m;++i) for(x1=0;x1<n&&i-x1>=0;++x1) for(x2=0;x2<n&&i-x2>=0;++x2) { if(x1-1>=0&&x2-1>=0) dp[i][x1][x2]=max(dp[i][x1][x2],dp[i-1][x1-1][x2-1]+M[x1][i-x1]+(x1==x2?0:M[x2][i-x2])); if(x1-1>=0&&i-x2-1>=0) dp[i][x1][x2]=max(dp[i][x1][x2],dp[i-1][x1-1][x2]+M[x1][i-x1]+(x1==x2?0:M[x2][i-x2])); if(x2-1>=0&&i-x1-1>=0) dp[i][x1][x2]=max(dp[i][x1][x2],dp[i-1][x1][x2-1]+M[x1][i-x1]+(x1==x2?0:M[x2][i-x2])); if(i-x2-1>=0&&i-x1-1>=0) dp[i][x1][x2]=max(dp[i][x1][x2],dp[i-1][x1][x2]+M[x1][i-x1]+(x1==x2?0:M[x2][i-x2])); } printf("%d\n",dp[n+m-1][n-1][n-1]); return 0; }
相关文章推荐
- 电脑闪屏
- Struts2动态方法调用
- __autoload自动加载类文件
- event 和 window.event
- 最小费用最大流
- 思维导图---“计算机硬件系统”练手
- Bootstrap CSS 代码
- iOS编程-------UITextField UIButton UITextFieldDelegate
- FMDB事务批量更新——IOS笔记
- HDU1709(母函数)
- C++primer学习:string的操作习题(1):
- 选择排序和归并排序
- RT2870 Wireless Lan Linux Driver
- Vagrant 启动报错:the "vboxsf" file system is not available
- mysql 数据类型与操作数据表
- **HDU 4276 - The Ghost Blows Light(树形DP)
- Android面试题总结(二)
- Android--Menu的实现 ActionMode
- TCP/IP协议面试常见题目
- CF582A给出n个数的相互GCD,求这n个数,map的使用