动态规划-多维DP
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划-多维DP相关的知识,希望对你有一定的参考价值。
P1541 乌龟棋
题目描述
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。
乌龟棋中M张爬行卡片,分成4种不同的类型(M张卡片中不一定包含所有4种类型的卡片,见样例),每种类型的卡片上分别标有1、2、3、4四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。
游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。
很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。
现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?
输入
输入文件的每行中两个数之间用一个空格隔开。
第1行2个正整数N和M,分别表示棋盘格子数和爬行卡片数。
第2行N个非负整数,a1a2……aN,其中ai表示棋盘第i个格子上的分数。
第3行M个整数,b1b2……bM,表示M张爬行卡片上的数字。
输入数据保证到达终点时刚好用光M张爬行卡片。
9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1
输出
输出只有1行,1个整数,表示小明最多能得到的分数。
73
说明
每个测试点1s
小明使用爬行卡片顺序为1,1,3,1,2,得到的分数为6+10+14+8+18+17=73。注意,由于起点是1,所以自动获得第1格的分数6。
对于30%的数据有1≤N≤30,1≤M≤12。
对于50%的数据有1≤N≤120,1≤M≤50,且4种爬行卡片,每种卡片的张数不会超过20。
对于100%的数据有1≤N≤350,1≤M≤120,且4种爬行卡片,每种卡片的张数不会超过40;0≤ai≤100,1≤i≤N;1≤bi≤4,1≤i≤M。
代码
P1006 传纸条
题目描述
小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要经由许多同学传到对方手里,小渊坐在矩阵的左上角,坐标(1,1),小轩坐在矩阵的右下角,坐标(m,n)。从小渊传到小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或者向左传递。
在活动进行中,小渊希望给小轩传递一张纸条,同时希望小轩给他回复。班里每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙。反之亦然。
还有一件事情需要注意,全班每个同学愿意帮忙的好感度有高有低(注意:小渊和小轩的好心程度没有定义,输入时用0表示),可以用一个0-100的自然数来表示,数越大表示越好心。小渊和小轩希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度只和最大。现在,请你帮助小渊和小轩找到这样的两条路径。
输入
输入文件message.in的第一行有2个用空格隔开的整数m和n,表示班里有m行n列(1<=m,n<=50)。
接下来的m行是一个m*n的矩阵,矩阵中第i行j列的整数表示坐在第i行j列的学生的好心程度。每行的n个整数之间用空格隔开。
3 3
0 3 9
2 8 5
5 7 0
说明【限制】
30%的数据满足:1<=m,n<=10
100%的数据满足:1<=m,n<=50
NOIP 2008提高组第三题
输出
输出文件message.out共一行,包含一个整数,表示来回两条路上参与传递纸条的学生的好心程度之和的最大值。
34
双线程DP (四维DP)
转移方程:
//双线程dp.....f[x1][y1][x2][y2]是当一次传纸条在(x1,y1)第二次在(x2,y2)时的最大值 int a1=max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1]); int a2=max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]); dp[i][j][k][l]=max(a1,a2)+a[i][j]+a[k][l]; if(i==k && j==l) {dp[i][j][k][l]-=a[i][j];}
每次选择最大值,两个DP同时进行,如果有冲突的话,一个暂停一步(减去a[i] [j]或者是a[k] [l]),这样就错开了
**O(n^2*m^2)代码**
#include <iostream> using namespace std; int dp[55][55][55][55]= {0}; int a[55][55]= {0}; int main() { // freopen ("传纸条.in","r",stdin); int m,n; cin>>m>>n; for (int i=1; i<=m; i++) { for(int j=1; j<=n; j++) { cin>>a[i][j]; } } for(int i=1; i<=m; i++) { for(int j=1; j<=n; j++) { for(int k=1; k<=m; k++) { for(int l=1; l<=n; l++) { int a1=max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1]); int a2=max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]); dp[i][j][k][l]=max(a1,a2)+a[i][j]+a[k][l]; if(i==k && j==l) { dp[i][j][k][l]-=a[i][j]; } } } } } cout<<dp[m][n][m][n]; }
四维优化
if((i != a || j != b) && i+j == a+b) { // “&&”后面是关键,可以节约很多时间,以接近三维的速度 dp[i][j][a][b] = max(dp[i-1][j][a-1][b],dp[i-1][j][a][b-1],dp[i][j-1][a-1][b],dp[i][j-1][a][b-1])+c[i][j]+c[a][b]; dp[m][n][m][n] = max(dp[m-1][n][m-1][n],dp[m-1][n][m][n-1],dp[m][n-1][m-1][n],dp[m][n-1][m][n-1]); }
三维压缩
另外压缩成三维是这样的,对于来到(x,y),那么它走的步数是(x-1)+(y-1),这个距离叫做曼哈顿距离。
由于(x1,y1)和(x2,y2)是同时进行的,所以x1+y1=x2+y2,所以y2=x1+y1-x2,利用这个结论我们就可以
变为f[x1][y1][x2]了,y2反正能推出来嘛。
以上是关于动态规划-多维DP的主要内容,如果未能解决你的问题,请参考以下文章