Rise in Price

这篇博客探讨了一个在网格中从左上角到右下角的最优化路径问题,每一步可以向右或向下移动,并且在每个单元格中可以收集钻石并提升其价值。目标是通过选择最佳路径最大化最终出售钻石的利润。输入包含网格尺寸、每个单元格的钻石数量和价格提升值,输出是最大可能的收益。解决方案涉及动态规划和路径合并策略。
摘要由CSDN通过智能技术生成

There are n × n cells on a grid, the top-left cell is at (1, 1) while the bottom-right cell is at (n, n). You start at (1, 1) and move to (n, n). At any cell (i, j), you can move to (i + 1, j) or (i, j + 1), provided that you don’t move out of the grid. Clearly, you will make exactly 2n − 2 steps. When you are at cell (i, j), including the starting point (1, 1) and the destination (n, n), you can take all the ai,j diamonds at this cell, and have a chance to raise the price of each diamond by bi,j dollars. You will sell all the diamonds you have with the final price in the end, and your goal is to choose the optimal path that will maximize your profits. Note that initially the price of each diamond is zero, and you have nothing to sell.

Input

The first line contains a single integer T (1 ≤ T ≤ 10), the number of test cases. For each test case: The first line contains a single integer n (1 ≤ n ≤ 100), denoting the size of the grid. Each of the following n lines contains n integers, the i-th line contains ai,1, ai,2, . . . , ai,n (1 ≤ ai,j ≤ 106 ), denoting the number of diamonds in each cell. Each of the following n lines contains n integers, the i-th line contains bi,1, bi,2, . . . , bi,n (1 ≤ bi,j ≤ 106 ), denoting how much you can raise the price in each cell. It is guaranteed that all the values of ai,j and bi,j are chosen uniformly at random from integers in [1, 106 ]. The randomness condition does not apply to the sample test case, but your solution must pass the sample as well.

Output

For each test case, output a single line containing an integer: the maximum number of dollars you can earn by selling diamonds.

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
typedef vector<P>V;
const int N=105;
int Case,n,m,i,j,k,a[N][N],b[N][N];ll ans;V f[N][N];P pool[1000005];
inline void ext(const P&t){
  while(m&&pool[m].second<=t.second)m--;
  if(!m||pool[m].first<t.first)pool[++m]=t;
}
inline void merge(const V&A,const V&B,V&C){
  int ca=A.size(),cb=B.size(),i=0,j=0;
  m=0;
  while(i<ca&&j<cb)ext(A[i].first<B[j].first?A[i++]:B[j++]);
  while(i<ca)ext(A[i++]);
  while(j<cb)ext(B[j++]);
  C.resize(m);
  for(i=0;i<m;i++)C[i]=pool[i+1];
}
int main(){
  scanf("%d",&Case);
  while(Case--){
    scanf("%d",&n);
    for(i=1;i<=n;i++)for(j=1;j<=n;j++)scanf("%d",&a[i][j]);
    for(i=1;i<=n;i++)for(j=1;j<=n;j++)scanf("%d",&b[i][j]);
    f[1][1].resize(1);
    f[1][1][0]=P(a[1][1],b[1][1]);
    for(i=1;i<=n;i++)for(j=1;j<=n;j++){
      if(i==1&&j==1)continue;
      if(i==1)f[i][j]=f[i][j-1];
      else if(j==1)f[i][j]=f[i-1][j];
      else merge(f[i-1][j],f[i][j-1],f[i][j]);
      for(k=0;k<f[i][j].size();k++){
        f[i][j][k].first+=a[i][j];
        f[i][j][k].second+=b[i][j];
      }
    }
    ans=0;
    for(i=0;i<f[n][n].size();i++)ans=max(ans,1LL*f[n][n][i].first*f[n][n][i].second);
    printf("%lld\n",ans);
  }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值