HDU 6981.Rise in Price

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:

  1. n的数据范围是100;
  2. 用暴力把每一条路径都走一遍,找最优解;
  3. 考虑剪枝函数;
  4. 假设当前已经拿到的钻石 ∑ 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
  5. 答案表示为 ( 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
  6. 如果我即将要走的点(向下或者向右)的估价值不能够更新答案的话,就剪枝掉;
  7. 为了写估价函数,令未来某条路径的权值之和为 C i = A i + B i C_i=A_i+B_i Ci=Ai+Bi
  8. 用动态规划写出C数组,使每个位置都对应一个 C m a x C_{max} Cmax
  9. C m a x = A + B C_{max} = A + B Cmax=A+B
  10. 已经走过的路径 S a S_a Sa S b S_b Sb已经是最优解不能更改了,能改变的只有未来怎么走,即 A A A B B B;
  11. 那么我们就要找到一个合适的 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)最大,就是整体最优解;
  12. B = C m a x − A B = C_{max}-A B=CmaxA 代入到 ( 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+(SbSa+Cmax)A+SaSb+SaCcmax,要使F最大,A就要取 − b 2 a -\frac{b}{2a} 2ab;
  13. 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=2SaSb+Cmax,B=2SbSa+Cmax
  14. 将A和B回代到函数F中就是一条路径的答案,如果这个答案不能更新ans,则剪枝;
  15. 代入得到 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;
  16. 运用小学完全平方公式 ( 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;
  17. 得到 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
  18. 下面深搜的过程看一下代码吧

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:

  1. 这道题加深了我对dfs的理解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值