
题意等价于:选择两条从A到B的路径,路径上的点对答案至多贡献一次,求最大值
很容易想到先计算第一条路径,再计算第二条路径(f[i1][j1][i2][j2]),判断重合的点,但这样没有利用重合点的必要性,有时间和空间上的冗余
进一步想到,每对重合点的横纵坐标之和必定相等
也就是说只有当i1 + j1 == i2 + j2时,两条路径上的点才有可能重合,这就是我们要特殊处理的情况
不妨设k = i1+j1,这样枚举的状态就从四维降到了三维,只需计算状态f[k][i1][i2]即可(两点重合等价于i1 == i2)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fr first
#define se second
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const int INF = 0X3f3f3f3f, N = 20, MOD = 1e9 + 10;
int w[N][N];
int f[2*N][N][N];
void work() {
int n;
cin>>n;
int a,b,c;
while(cin>>a>>b>>c,a||b||c) w[a][b]=c;
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 && j2 && j1<=n && j2<=n){
int t=w[i1][j1];
if(i1!=i2) t+=w[i2][j2];
// cout<<t<<endl;
int &x=f[k][i1][i2];
x=max(x,f[k-1][i1][i2]+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-1][i2-1]+t);
}
}
}
cout<<f[2*n][n][n]<<endl;
}
signed main() {
work();
return 0;
}