学习随笔
方格取数
- 动态规划问题
- 数字三角形
题目具体链接
题目描述:找到一个矩阵中,两条线路之和最大的情况,并且把最大值输出
- 数字三角形
#include <iostream>
#include<algorithm>
using namespace std;
const int N = 15;
int n;
int w[N][N], f[N * 2][N][N];//三维来记录两个人的位置,两个人同时走
//两个小朋友同时走k步,从(1,1),(1,1)走到(i1,j1),(i2,j2)能获得的最大花生数目.
int main() {
cin >> n;
int a, b, c;
while (cin >> a >> b >> c)
{
w[a][b] = c;
if (a || b || c) break;
}
for (int k = 2; k <= 2 * n; k++)
{
for (int i1 = 1; i1 <= n; i1++)
{
for (int i2 = 1; i2 <= n; i2++)
{
int j1 = k - i1, j2 = k - i2;
if (j1 >= 1 && j1 <= n&&j2 >= 1 && j2 <= n)
{
// 不能越界
int &x = f[k][i1][i2];//声明x是f[k][i1][i2]的别名
int t = w[i1][j1];//单个权重
if (i1 != i2) t += w[i2][j2];//位置不同
//不重合则需要加两个权重.
x = max(x, f[k - 1][i1 - 1][i2 - 1] + t);//都向下走
x = max(x, f[k - 1][i1 - 1][i2] + t);//一个向下,一个向右
x = max(x, f[k - 1][i1][i2 - 1] + t);//一个向右一个向下
x = max(x, f[k - 1][i1][i2] + t);//都向右
//保留最大属性
}
}
}
}
cout << f[n * 2][n][n] << endl;
return 0;
}
学习产出:
1、 用的是f[N*2][N] 用前面的来记录步数,后面的记录其中一条路线当前所在的位置,当同时走的时候,就可以用来记录多条路线之和
2、int &x = f[k][i1][i2]; 当要输出的值很长时,用&别称可以,简化输出。
3、f[k][i1][i2];代表的是两个位置(i1,k-i1)和(i2,k-i2),有两个点,达到这个位置,并且要保证两个点一起走,可以1号点向下,2号点向下或者1号点向下,2号点向右,简化向下为0 向右为1 则是00 01 10 11四种情况。代表的含义是,f[k][i1][i2]取这四种情况的最大值
递推式:
x = max(x, f[k - 1][i1 - 1][i2 - 1] + t);//都向下走
x = max(x, f[k - 1][i1 - 1][i2] + t);//一个向下,一个向右
x = max(x, f[k - 1][i1][i2 - 1] + t);//一个向右一个向下
x = max(x, f[k - 1][i1][i2] + t);//都向右
以此思想推广
用f[N*2][N] [N][N]就可以记录在二维数组中的三条线路,并且递推公式可以的出是(简化向下为0 向右为1)000、001、010、011、100、101、110、111 八种情况的最大值。
发现: 根据观察发现,由于在同一个点不能取两次值,则根据题目要求取最大值的特性,多条线路不可能重合,因为这会导致重合点重复。也就是说正确的解,两条线路一定是一上一下的。
具体解释感谢vlehr