思路一、
只走一次:
f[i,j]表示所有从(1,1)走到(i,j)的路径的最大值f[i,j]= max(f[i-1,j]+ w[i], f[i-1][j]+ w[i])
走两次:
f[i1,j1,i2,j2]表示所有从(1,1),(1,1)分别走到(i1,j1),(i2,j2)的路径的最大值
那么:如何处理"同—个格子不能被重复选择"?
只有在i1 + j1 == i2 +j2时,两条路径的格子才可能重合
f[k, i1, i2]表示所有从(1,1),(1,1)分别走到(i1,k-i1), (i2,k-i2)的路径的最大值
k表示两条路线当前走到的格子的横纵坐标之和
k = i1 + j1 = i2+ j2
因此把状态由f[i1][j1][i2][j2]优化成三维 f[k][i1][i2]
等价于 [i1][k−i1][i2]k−i2]
状态转移方程的求解:
考虑四种走法:
第一条:从上面来 第二条:从左边来
f[i1-1]][j1][i2-1][j2]==f[k-1][i1-1][i2-1];
第一条:从上面来 第二条:从左边来
f[i1-1][j1][i2][j2-1]==f[k-1][i1-1][i2];
第一条:从左边来 第二条:从上边来
f[i1][j1-1][i2-1][j2]==f[k-1][i1][i2-1];
第一条:从左边来 第二条:从左边来
f[i1][j1-1][i2][j2-1]==f[k-1][i1][i2];
代码书写:
写输入
k从2开始增加(从1,1开始)
i1从1增加
i2从1增加
规定j1=k-i1;j2=k-i2;
约束边界条件:if (j1 >= 1 && j1 <= n && j2 >= 1 && j2 <= n)
t值作为方格值
完整代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 15;
int n;
int w[N][N];
int f[N * 2][N][N];
int main()
{
scanf("%d", &n);
int a, b, c;
while (cin >> a >> b >> c, a || b || c) w[a][b] = c;
for (int k = 2; k <= n + 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 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);
}
}
printf("%d\n", f[n + n][n][n]);
return 0;
}
思路二
代码:
#include <iostream>
using namespace std;
const int N = 20;
int n;
int a[N][N];
int f[N][N][N][N];
int main () {
cin >> n;
while (true) {
int x,y,w;
cin >> x >> y >> w;
if (!x && !y && !w) break;
a[x][y] += w;
}
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 &ans = f[i1][j1][i2][j2];
ans = max (ans,f[i1 - 1][j1][i2 - 1][j2]);
ans = max (ans,f[i1 - 1][j1][i2][j2 - 1]);
ans = max (ans,f[i1][j1 - 1][i2 - 1][j2]);
ans = max (ans,f[i1][j1 - 1][i2][j2 - 1]);
if (i1 == i2 && j1 == j2) ans += a[i1][j1];
else ans += a[i1][j1] + a[i2][j2];
}
}
}
}
cout << f[n][n][n][n] << endl;
return 0;
}
题外话:
1、这道题要知道输入:
while(1){
int x,y,z;
if(x==0&&y==0&&z==0)break;
cin >> x >> y >> z;
a[x][y] += z; //给相应的格子对应值
}
2、会写cin>>x >>y >>z;
3、会写break;
4、本题的意思是,选过一次后,就会变为0,而不是连0都不能选了:可以选0的啊!这个时候加只加一个值就行了,而不是加两个值。