https://acm.hdu.edu.cn/showproblem.php?pid=6981

 

题意:

给出2个n*n的矩阵A和B

起点在(1,1),终点在(n,n),每步只能往右或者往下走

得分为路径上的A的和与B的和的乘积

问最大得分

数据随机

 

解法一:搜索剪枝

因为是随机数据,估价函数优秀一些大概率还是可以过的

参考的这位大佬的做法

https://blog.csdn.net/George_Plover/article/details/119151411

设现在走过的A矩阵的和为sa,将来要走的和为a,现在走过的B矩阵的和为sb,将来要走的和为b

那么总乘积和可以表示为(sa+a)*(sb+b)=sa*sb+sa*b+sb*a+a*b

令C=A+B

则乘积和=sa*sb+sa*(c-a)+sb*a+a*(c-a)

假设当前位置右下角的数我们可以自由调整

c越大,乘积和越大

令Cmax表示当前位置右下角还能获取的最大的A+B之和

式子sa*sb+sa*(Cmax-a)+sb*a+a*(Cmax-a)是一个二元一次方程

当a=(sb-sa+Cmax)/2 时,方程的值最大,Cmax-a可求出对应的b

就可以用这个a b Cmax做最优化剪枝

#include<bits/stdc++.h>

using namespace std;

#define N 101

int n;
int a[N][N],b[N][N],c[N][N];

long long ans;

void dfs(int x,int y,int sa,int sb)
{
    if(x==n && y==n)
    {
        ans=max(ans,1ll*sa*sb);
        return;
    }
    int aa,bb;
    if(x<n)
    {
        aa=sb-sa+c[x+1][y]>>1;
        bb=sa+c[x+1][y]-sb>>1;
        if(1ll*(sa+aa)*(sb+bb)>ans) dfs(x+1,y,sa+a[x+1][y],sb+b[x+1][y]);
    }
    if(y<n)
    {
        aa=sb-sa+c[x][y+1]>>1;
        bb=sa+c[x][y+1]-sb>>1;
        if(1ll*(sa+aa)*(sb+bb)>ans) dfs(x,y+1,sa+a[x][y+1],sb+b[x][y+1]);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                scanf("%d",&a[i][j]);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                scanf("%d",&b[i][j]);
        for(int i=n;i;--i)
            for(int j=n;j;--j)
            {
                c[i][j]=a[i][j]+b[i][j];
                if(i<n) c[i][j]=max(c[i][j],a[i][j]+b[i][j]+c[i+1][j]);
                if(j<n) c[i][j]=max(c[i][j],a[i][j]+b[i][j]+c[i][j+1]);
            }
        ans=0;
        dfs(1,1,a[1][1],b[1][1]);
        printf("%lld\n",ans);
    }
}
View Code

相关文章: