Issue:
meaning:
给出一个n × \times ×n的矩阵,每个位置都有两个权值 a i j a_{ij} aij, b i j b_{ij} bij,要求从(1,1)出发,每次只能向右或者向下走,问:走到(n,n)的所有路径中, ∑ a i j × ∑ b i j \sum{a_{ij}}\times\sum{b_{ij}} ∑aij×∑bij 的最大值为多少。
Thinking:
- n的数据范围是100;
- 用暴力把每一条路径都走一遍,找最优解;
- 考虑剪枝函数;
- 假设当前已经拿到的钻石 ∑ a i j = S a \sum{a_{ij}}=S_a ∑aij=Sa,当前已经提高的价格 ∑ b i j = S b \sum{b_{ij}}=S_b ∑bij=Sb,还没有取到的钻石 ∑ a i j = A \sum{a_{ij}}=A ∑aij=A,还没有提高的价格 ∑ b i j = B \sum{b_{ij}}=B ∑bij=B;
- 答案表示为 ( S a + A ) × ( S b + B ) = S a × S b + S a × B + A × S b + A × B (S_a+A)\times(S_b+B)=Sa \times S_b +S_a \times B+A \times S_b+A\times B (Sa+A)×(Sb+B)=Sa×Sb+Sa×B+A×Sb+A×B;
- 如果我即将要走的点(向下或者向右)的估价值不能够更新答案的话,就剪枝掉;
- 为了写估价函数,令未来某条路径的权值之和为 C i = A i + B i C_i=A_i+B_i Ci=Ai+Bi;
- 用动态规划写出C数组,使每个位置都对应一个 C m a x C_{max} Cmax;
- C m a x = A + B C_{max} = A + B Cmax=A+B;
- 已经走过的路径 S a S_a Sa和 S b S_b Sb已经是最优解不能更改了,能改变的只有未来怎么走,即 A A A和 B B B;
- 那么我们就要找到一个合适的 A A A和 B B B使得函数 F = ( S a + A ) × ( S b + B ) F = (S_a+A)\times(S_b+B) F=(Sa+A)×(Sb+B)最大,就是整体最优解;
- 将 B = C m a x − A B = C_{max}-A B=Cmax−A 代入到 ( S a + A ) × ( S b + B ) (S_a+A)\times(S_b+B) (Sa+A)×(Sb+B) 中,得到二次函数 F = − A 2 + ( S b − S a + C m a x ) A + S a S b + S a C c m a x F = -A^2 + (S_b - S_a + C_{max})A + S_aS_b + S_aC_{cmax} F=−A2+(Sb−Sa+Cmax)A+SaSb+SaCcmax,要使F最大,A就要取 − b 2 a -\frac{b}{2a} −2ab;
- A = S a − S b + C m a x 2 , B = S b − S a + C m a x 2 A = \frac{S_a - S_b + C_{max}}{2}, B = \frac{S_b - S_a + C_{max}}{2} A=2Sa−Sb+Cmax,B=2Sb−Sa+Cmax;
- 将A和B回代到函数F中就是一条路径的答案,如果这个答案不能更新ans,则剪枝;
- 代入得到 F = 1 4 S a 2 + 1 4 S b 2 + 1 4 C m a x 2 + 1 2 S a S b + 1 2 S a C m a x + 1 2 S b C m a x F = \frac{1}{4}S_a^2 + \frac{1}{4}S_b^2 + \frac{1}{4}C_{max}^2 + \frac{1}{2}S_aS_b + \frac{1}{2}S_aC_{max} + \frac{1}{2}S_bC_{max} F=41Sa2+41Sb2+41Cmax2+21SaSb+21SaCmax+21SbCmax;
- 运用小学完全平方公式 ( a + b + c ) 2 = a 2 + b 2 + c 2 + 2 a b + 2 a c + 2 b c (a+b+c)^2 = a^2 +b^2+c^2+2ab+2ac+2bc (a+b+c)2=a2+b2+c2+2ab+2ac+2bc;
- 得到 F = ( S a + S b + C m a x 2 ) 2 F = (\frac{S_a+S_b+C_{max}}{2})^2 F=(2Sa+Sb+Cmax)2
- 下面深搜的过程看一下代码吧
Algorithm:
启发式搜索
Code:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 105;
int a[N][N], b[N][N], c[N][N];
int ans, n;
int get(int Sa, int Sb, int Cmax)
{
return Sa + Sb + Cmax >> 1;
}
void dfs(int x, int y, int Sa, int Sb)
{
if (x == n && y == n)
{
ans = max(ans, Sa*Sb);
return;
}
int t = get(Sa, Sb, c[x + 1][y]);
if (x < n && t * t > ans)
{
dfs(x + 1, y, Sa + a[x + 1][y], Sb + b[x + 1][y]);
}
t = get(Sa, Sb, c[x][y + 1]);
if (y < n && t * t > ans)
{
dfs(x, y + 1, Sa + a[x][y + 1], Sb + b[x][y + 1]);
}
}
signed main()
{
int T;
cin >> T;
while (T -- )
{
cin >> n;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ ) cin >> a[i][j];
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ ) cin >> b[i][j];
for (int i = n; i >= 1; i -- )
for (int j = n; j >= 1; j -- )
{
c[i][j] = a[i][j] + b[i][j];
if (i < n) c[i][j] = max(c[i][j], c[i + 1][j] + a[i][j] + b[i][j]);
if (j < n) c[i][j] = max(c[i][j], c[i][j + 1] + a[i][j] + b[i][j]);
}
ans = 0;
dfs(1, 1, a[1][1], b[1][1]);
cout << ans << endl;
}
return 0;
}
Tips:
- 这道题加深了我对dfs的理解