首先容易想到的是每一格都是由上或左转移而来,并且经过格子必将钻石取完。dp的话空间不够,所以思考其他方法。
由于每格转移到本格都是增加本格的数量和价值,所以我们只需要考虑到本格之前的最佳状态即可。
因为状态由两部分组成-价值和数量,价值乘数量大的肯定优。所以我们存下所有可能的状态,从其中挑选最优的一些解转移。所有的状态有 C 2 n n C_{2n}^n C2nn个,经过优化只有几千个状态有可能~~(出题人说的,我还是没法严谨的推出来结果)~~ 。
#include "bits/stdc++.h"
#define int long long
using namespace std;
int a[200][200];
int b[200][200];
vector<pair<int, int>> p[200][200];
signed main() {
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
cin >> a[i][j];
p[i][j].clear();
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
cin >> b[i][j];
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (i == 1 && j == 1) {
p[i][j].push_back({
a[i][j], b[i][j]});
continue;
}
else if (i == 1) p[i][j].push_back(p[i][j - 1][0]);
else if (j == 1) p[i][j].push_back(p[i - 1][j][0]);
else {
int p1 = 0, p2 = 0;
while (p[i][j].size() < 100) {
if (p1 < p[i][j-1].size() && p2 < p[i-1][j].size()) {
if (p[i][j - 1][p1].first * p[i][j - 1][p1].second >
p[i - 1][j][p2].first * p[i - 1][j][p2].second) {
p[i][j].push_back(p[i][j - 1][p1]);
p1++;
} else {
p[i][j].push_back(p[i - 1][j][p2]);
p2++;
}
} else if (p1 < p[i][j-1].size()){
p[i][j].push_back(p[i][j - 1][p1]);
p1++;
} else if (p2 < p[i-1][j].size())
{
p[i][j].push_back(p[i - 1][j][p2]);
p2++;
} else break;
}
}
for (int k = 0; k < p[i][j].size(); ++k) {
p[i][j][k].first += a[i][j];
p[i][j][k].second += b[i][j];
}
sort(p[i][j].begin(), p[i][j].end(), [&](pair<int, int> tmp1, pair<int, int> tmp2) {
return tmp1.first * tmp1.second > tmp2.first * tmp2.second;
});
}
}
cout << p[n][n][0].first * p[n][n][0].second << endl;
}
}