设有 N×N 的方格图,我们在其中的某些方格中填入正整数,而其它的方格中则放入数字0。如下图所示:
某人从图中的左上角 A 出发,可以向下行走,也可以向右行走,直到到达右下角的 B 点。
在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
此人从 A 点到 B 点共走了两次,试找出两条这样的路径,使得取得的数字和为最大。
输入格式
第一行为一个整数N,表示 N×N 的方格图。
接下来的每行有三个整数,第一个为行号数,第二个为列号数,第三个为在该行、该列上所放的数。
一行“0 0 0”表示结束。
输出格式
输出一个整数,表示两条路径上取得的最大的和。
数据范围
N≤10
输入样例:
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
分析:
本 题 核 心 问 题 在 于 解 决 “ 每 个 点 的 值 只 加 一 次 ” 的 问 题 。 本题核心问题在于解决“每个点的值只加一次”的问题。 本题核心问题在于解决“每个点的值只加一次”的问题。
事 实 上 , 每 次 走 一 步 , 要 么 行 增 加 1 , 要 么 列 增 加 1 。 因 此 , 整 个 过 程 可 以 分 为 k 步 , k 从 1 增 加 到 n + m 。 我 们 同 时 进 行 2 个 路 径 的 计 算 , 只 要 确 定 一 条 路 径 的 横 坐 标 , 就 能 确 定 这 条 路 径 的 纵 坐 标 j = k − i 。 若 点 ( i 1 , y 1 ) 与 ( i 2 , y 2 ) 重 合 , 则 i 1 = i 2 。 这 是 因 为 k = i 1 + j 1 = i 2 + j 2 。 事实上,每次走一步,要么行增加1,要么列增加1。\\因此,整个过程可以分为k步,k从1增加到n+m。\\我们同时进行2个路径的计算,只要确定一条路径的横坐标,就能确定这条路径的纵坐标j=k-i。\\若点(i_1,y_1)与(i_2,y_2)重合,则i_1=i_2。这是因为k=i_1+j_1=i_2+j_2。 事实上,每次走一步,要么行增加1,要么列增加1。因此,整个过程可以分为k步,k从1增加到n+m。我们同时进行2个路径的计算,只要确定一条路径的横坐标,就能确定这条路径的纵坐标j=k−i。若点(i1,y1)与(i2,y2)重合,则i1=i2。这是因为k=i1+j1=i2+j2。
状 态 表 示 : f [ k ] [ i 1 ] [ i 2 ] : 前 k 步 中 , 第 一 条 路 径 的 横 坐 标 从 1 到 i 1 , 第 二 条 路 径 的 横 坐 标 从 1 到 i 2 的 合 计 最 大 收 益 。 状态表示:f[k][i_1][i_2]:前k步中,第一条路径的横坐标从1到i_1,第二条路径的横坐标从1到i_2的合计最大收益。 状态表示:f[k][i1][i2]:前k步中,第一条路径的横坐标从1到i1,第二条路径的横坐标从1到i2的合计最大收益。
状 态 计 算 : 首 先 判 断 i 1 是 否 等 于 i 2 , 若 i 1 ≠ i 2 , 说 明 两 点 不 重 合 , 记 第 k 步 收 益 为 t = w [ i 1 ] [ k − i 1 ] + w [ i 2 ] [ k − i 2 ] 。 若 i 1 = i 2 , 则 记 t = w [ i 1 ] [ k − i 1 ] 。 ① 、 ( i 1 , y 1 ) 由 ( i 1 − 1 , j 1 ) 转 移 而 来 , ( i 2 , y 2 ) 由 ( i 2 − 1 , y 2 ) 转 移 而 来 : f [ k ] [ i 1 ] [ i 2 ] = f [ k − 1 ] [ i 1 − 1 ] [ i 2 − 1 ] + t 。 状态计算:\\首先判断i_1是否等于i_2,\\若i_1≠i_2,说明两点不重合,记第k步收益为t=w[i_1][k-i_1]+w[i_2][k-i_2]。\\若i_1=i_2,则记t=w[i_1][k-i_1]。\\ \ \\①、(i_1,y_1)由(i_1-1,j_1)转移而来,(i_2,y_2)由(i_2-1,y_2)转移而来:f[k][i_1][i_2]=f[k-1][i_1-1][i_2-1]+t。 状态计算:首先判断i1是否等于i2,若i1=i2,说明两点不重合,记第k步收益为t=w[i1][k−i1]+w[i2][k−i2]。若i1=i2,则记t=w[i1][k−i1]。 ①、(i1,y1)由(i1−1,j1)转移而来,(i2,y2)由(i2−1,y2)转移而来:f[k][i1][i2]=f[k−1][i1−1][i2−1]+t。
② 、 ( i 1 , y 1 ) 由 ( i 1 − 1 , y 1 ) 转 移 而 来 , ( i 2 , y 2 ) 由 ( i 2 , y 2 − 1 ) 转 移 而 来 : f [ k ] [ i 1 ] [ i 2 ] = f [ k − 1 ] [ i 1 − 1 ] [ i 2 ] + t 。 ②、(i_1,y_1)由(i_1-1,y_1)转移而来,(i_2,y_2)由(i_2,y_2-1)转移而来:f[k][i_1][i_2]=f[k-1][i_1-1][i_2]+t。 ②、(i1,y1)由(i1−1,y1)转移而来,(i2,y2)由(i2,y2−1)转移而来:f[k][i1][i2]=f[k−1][i1−1][i2]+t。
③ 、 ( i 1 , y 1 ) 由 ( i 1 , y 1 − 1 ) 转 移 而 来 , ( i 2 , y 2 ) 由 ( i 2 − 1 , y 2 ) 转 移 而 来 : f [ k ] [ i 1 ] [ i 2 ] = f [ k − 1 ] [ i 1 ] [ i 2 − 1 ] + t 。 ③、(i_1,y_1)由(i_1,y_1-1)转移而来,(i_2,y_2)由(i_2-1,y_2)转移而来:f[k][i_1][i_2]=f[k-1][i_1][i_2-1]+t。 ③、(i1,y1)由(i1,y1−1)转移而来,(i2,y2)由(i2−1,y2)转移而来:f[k][i1][i2]=f[k−1][i1][i2−1]+t。
④ 、 ( i 1 , y 1 ) 由 ( i 1 , y 1 − 1 ) 转 移 而 来 , ( i 2 , y 2 ) 由 ( i 2 , y 2 − 1 ) 转 移 而 来 : f [ k ] [ i 1 ] [ i 2 ] = f [ k − 1 ] [ i 1 ] [ i 2 ] + t 。 ④、(i_1,y_1)由(i_1,y_1-1)转移而来,(i_2,y_2)由(i_2,y_2-1)转移而来:f[k][i_1][i_2]=f[k-1][i_1][i_2]+t。 ④、(i1,y1)由(i1,y1−1)转移而来,(i2,y2)由(i2,y2−1)转移而来:f[k][i1][i2]=f[k−1][i1][i2]+t。
代码:
#include
#include
using namespace std;
const int N=15;
int n,w[N][N],f[N*2][N][N];
int main()
{
cin>>n;
int x,y,v;
while(cin>>x>>y>>v,x||y||v) w[x][y]=v;
for(int k=2;k<=n*2;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 t=w[i1][j1];
if(i1!=i2) t+=w[i2][j2];
int &x=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);
}
}
cout<<f[2*n][n][n]<<endl;
return 0;
}
小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。
一次素质拓展活动中,班上同学安排坐成一个 m 行 n 列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。
幸运的是,他们可以通过传纸条来进行交流。
纸条要经由许多同学传到对方手里,小渊坐在矩阵的左上角,坐标(1,1),小轩坐在矩阵的右下角,坐标(m,n)。
从小渊传到小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或者向左传递。
在活动进行中,小渊希望给小轩传递一张纸条,同时希望小轩给他回复。
班里每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙,反之亦然。
还有一件事情需要注意,全班每个同学愿意帮忙的好感度有高有低(注意:小渊和小轩的好心程度没有定义,输入时用0表示),可以用一个0-100的自然数来表示,数越大表示越好心。
小渊和小轩希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度之和最大。
现在,请你帮助小渊和小轩找到这样的两条路径。
输入格式
第一行有2个用空格隔开的整数 m 和 n,表示学生矩阵有 m 行 n 列。
接下来的 m 行是一个 m∗n 的矩阵,矩阵中第 i 行 j 列的整数表示坐在第 i 行 j 列的学生的好心程度,每行的 n 个整数之间用空格隔开。
输出格式
输出一个整数,表示来回两条路上参与传递纸条的学生的好心程度之和的最大值。
数据范围
1≤n,m≤50
输入样例:
3 3
0 3 9
2 8 5
5 7 0
输出样例:
34
分析:
题 中 说 从 ( 1 , 1 ) 到 ( n , m ) 同 时 从 ( n , m ) 到 ( 1 , 1 ) , 求 合 计 最 大 收 益 。 其 实 正 向 反 向 是 不 影 响 计 算 过 程 的 , 代 码 同 上 。 题中说从(1,1)到(n,m)同时从(n,m)到(1,1),求合计最大收益。\\其实正向反向是不影响计算过程的,代码同上。 题中说从(1,1)到(n,m)同时从(n,m)到(1,1),求合计最大收益。其实正向反向是不影响计算过程的,代码同上。
代码:
#include
#include
using namespace std;
const int N=55;
int n,m,w[N][N],f[2*N][N][N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>w[i][j];
for(int k=2;k<=n+m;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<=m&&j2>=1&&j2<=m)
{
int t=w[i1][j1];
if(i1!=i2) t+=w[i2][j2];
int &x=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);
}
}
cout<<f[n+m][n][n]<<endl;
return 0;
}