参考闫氏 d p 分析法 参考闫氏dp分析法 参考闫氏dp分析法
方格取数
f [ i 1 ] [ j 1 ] [ i 2 ] [ j 2 ] 表示( 1 , 1 )到( i 1 , j 1 )和( 1 , 1 )到 ( i 2 , j 2 ) 和的最大值 f[i1][j1][i2][j2]表示(1,1)到(i1,j1)和(1,1)到(i2,j2)和的最大值 f[i1][j1][i2][j2]表示(1,1)到(i1,j1)和(1,1)到(i2,j2)和的最大值
利用最后一步不同的思想,找个集合可以由四种状态转移过来 利用最后一步不同的思想,找个集合可以由四种状态转移过来 利用最后一步不同的思想,找个集合可以由四种状态转移过来
分别是 ( i 1 , j 1 ) 由 ( i 1 − 1 , j 1 ) 向下得来或者 ( i 1 , j 1 − 1 ) 向右得来的两种情况和 ( i 2 , j 1 ) 分别由 ( i 2 − 1 , j 2 ) , ( i 2 , j 2 − 1 ) 两种情况组合而成 分别是(i1,j1)由(i1-1,j1)向下得来或者(i1,j1-1)向右得来的两种情况和(i2,j1)分别由(i2-1,j2),(i2,j2-1)两种情况组合而成 分别是(i1,j1)由(i1−1,j1)向下得来或者(i1,j1−1)向右得来的两种情况和(i2,j1)分别由(i2−1,j2),(i2,j2−1)两种情况组合而成
这个题还有个限制就是每个方格只能取一次,所有 ( i 1 , j 1 ) , ( i 2 , j 2 ) 到了相同的点只需要加一次权值 这个题还有个限制就是每个方格只能取一次,所有(i1,j1),(i2,j2)到了相同的点只需要加一次权值 这个题还有个限制就是每个方格只能取一次,所有(i1,j1),(i2,j2)到了相同的点只需要加一次权值
四维代码
#include
using namespace std;
const int N = 12;
int n, x, y, c;
int f[N][N][N][N];
int w[N][N];
int main(){
cin >> n;
while((cin >> x >> y >> c), (x && y && c)){
w[x][y] = c;
}
for(int i1 = 1; i1 <= n; i1 ++)
{
for(int j1 = 1; j1 <= n; j1 ++)
{
for(int i2 = 1; i2 <= n; i2 ++)
{
for(int j2 = 1; j2 <= n; j2 ++)
{
int &v = f[i1][j1][i2][j2];
v = f[i1-1][j1][i2-1][j2] + w[i1][j1];
v = max(f[i1][j1-1][i2-1][j2] + w[i1][j1], v);
v = max(f[i1-1][j1][i2][j2-1] + w[i1][j1], v);
v = max(f[i1][j1-1][i2][j2-1] + w[i1][j1], v);
if(i1 != i2 && j1 != j2)
{
v += w[i2][j2];
}
}
}
}
}
cout << f[n][n][n][n];
return 0;
}
四维的 f [ i 1 ] [ j 1 ] [ i 2 ] [ j 2 ] 是 ( 1 , 1 ) ( 1 , 1 ) 到 ( i 1 , j 1 ) ( i 2 , j 2 ) 路线的集合 四维的f[i1][j1][i2][j2]是(1,1)(1,1)到(i1,j1)(i2,j2)路线的集合 四维的f[i1][j1][i2][j2]是(1,1)(1,1)到(i1,j1)(i2,j2)路线的集合
我们发现重合点一定是偏移量相同时 ( i 1 + j 1 = = i 2 + j 2 ) 才可能重合 我们发现重合点一定是偏移量相同时(i1+j1==i2+j2)才可能重合 我们发现重合点一定是偏移量相同时(i1+j1==i2+j2)才可能重合
上面那个思路 i 1 + j 1 和 i 2 + j 2 是没关系的,但我们可以加一个 k 当作偏移量 上面那个思路i1+j1和i2+j2是没关系的,但我们可以加一个k当作偏移量 上面那个思路i1+j1和i2+j2是没关系的,但我们可以加一个k当作偏移量
k = i 1 + j 1 = i 2 + j 2 k=i1+j1=i2+j2 k=i1+j1=i2+j2
这样 f [ k ] [ i 1 ] [ i 2 ] 就相当于偏移量相同的 ( 1 , 1 ) ( 1 , 1 ) 到 ( i 1 , k − i 1 ) ( i 2 , k − i 2 ) 这样f[k][i1][i2]就相当于偏移量相同的(1,1)(1,1)到(i1,k-i1)(i2,k-i2) 这样f[k][i1][i2]就相当于偏移量相同的(1,1)(1,1)到(i1,k−i1)(i2,k−i2)
这样我们就实现了代码的优化 这样我们就实现了代码的优化 这样我们就实现了代码的优化
三维代码
#include
using namespace std;
const int N = 25;
int n, x, y, c;
int f[N][N][N];
int w[N][N];
int main(){
cin >> n;
while((cin >> x >> y >> c), (x && y && c)){
w[x][y] = c;
}
//k是x+y的偏移量(i1,j1),(i2,j2)都是k偏移量时的最大和
for(int k = 2; k <= n << 1; k ++)
{
for(int i1 = 1; i1 <= n; i1 ++)
{
for(int i2 = 1; i2 <= n; i2 ++)
{
int j1 = k - i1;
int j2 = k - i2;
if(j1 >=1 && j1 <= n && j2 >=1 && j2 <= n)
{
int &v = f[k][i1][i2];
int tem = w[i1][j1];
v = max(v, f[k-1][i1-1][i2-1] + tem);
v = max(v, f[k-1][i1][i2] + tem);
v = max(v, f[k-1][i1][i2-1] + tem);
v = max(v, f[k-1][i1-1][i2] + tem);
if(i1 != i2) v += w[i2][j2];
}
}
}
}
cout << f[2*n][n][n] << endl;
return 0;
}
扩展 扩展 扩展
传字条的题目与这个题目的区别就是重复的点不可以过,而这个题是重复的点可以过但取为 0 传字条的题目与这个题目的区别就是重复的点不可以过,而这个题是重复的点可以过但取为0 传字条的题目与这个题目的区别就是重复的点不可以过,而这个题是重复的点可以过但取为0
但是相同的代码可以同样 a c 原因就是在递推的过程中虽然枚举了重复的点,但这个重复的点一定不是最优解,会被最终的最优解覆盖掉,最终答案也一定是不含重复点的两条路线的最大和 但是相同的代码可以同样ac原因就是在递推的过程中虽然枚举了重复的点,但这个重复的点一定不是最优解,会被最终的最优解覆盖掉,最终答案也一定是不含重复点的两条路线的最大和 但是相同的代码可以同样ac原因就是在递推的过程中虽然枚举了重复的点,但这个重复的点一定不是最优解,会被最终的最优解覆盖掉,最终答案也一定是不含重复点的两条路线的最大和