方格取数()

 思路:这道题和摘花生一样,从 左上到右下,每次只能往左走或者往右走,不同的是,从左上到右下要走两次,且每次走过,方格数就变为0,所以要特判是否走到了同一个点;

本题的思路是有两个人一起走,

朴素思路是:

f[i1][j1][i2][j2] //表示从(1,1),(1,1)走到[i1][j1],[i2][j2]最大的值

//状态转移方程:
f[i1][j1][i2][j2]=max(f[i1-1][j1][i2-1][j2]+t,f[i1-1][j1][i2][j2-1]+t,f[i1][j1-1][i2-1][j2]+t,f[i1][j1-1][i2][j2-1]+t)

//t表示两个人走的两格加的权值
//如果相同加一个权值
#include<iostream>

using namespace std;

const int N = 15;
int w[N][N];
int g[N][N][N][N];


int main()
{
    int n;
    cin>>n;
    int a,b,c;
    while(cin>>a>>b>>c,a!=0&&b!=0&&c!=0)
    {
        w[a][b]=c;
    }
    
    for(int i1=1;i1<=n;i1++)
    {
        for(int j1=1;j1<=n;j1++)
        {
            for(int i2=1;i2<=n;i2++)
            {
                for(int j2=1;j2<=n;j2++)
                {
                    int t=w[i1][j1];
                    if(i1!=i2||j1!=j2) t+=w[i2][j2];
                    
                    int &v=g[i1][j1][i2][j2];
                    v=max(v,g[i1-1][j1][i2-1][j2]+t);
                    v=max(v,g[i1][j1-1][i2][j2-1]+t);
                    v=max(v,g[i1-1][j1][i2][j2-1]+t);
                    v=max(v,g[i1][j1-1][i2-1][j2]+t);
                }
            }
        }
    }
    cout<<g[n][n][n][n]<<endl;
    return 0;
}

根据上述内容,我们可以发现只有当 i1+j1 == i2+j2 时两者才可能走到同一个格子

这时我们可以优化掉一个纬度,用k表示 i1+j1 和 i2+j2 ,这时只需要枚举k,i1,i2三个常数

#include<iostream>

using namespace std;

const int N = 12;
int f[N*2][N][N];
int w[N][N];
int main()
{
    int n;
    cin>>n;
    int a,b,c;
    while(cin>>a>>b>>c,a!=0||b!=0||c!=0) w[a][b]=c;
    
    for(int k=2;k<=n+n;k++)
    {
        for(int i1=1;i1<=n;i1++)
        {
            for(int i2=1;i2<=n;i2++)
            {
                int j1=k-i1,j2=k-i2;
                if(j1>=1&&j1<=n&&j2>=1&&j2<=n)//注意边界
                {
                    int t=w[i1][j1];
                    if(i1!=i2) t+=w[i2][j2];
                    
                    int &v=f[k][i1][i2];
                    v=max(v,f[k-1][i1-1][i2-1]+t);//k-1表示上一个状态,
                    v=max(v,f[k-1][i1][i2-1]+t);//在k状态下,可以有k-1
                    v=max(v,f[k-1][i1-1][i2]+t);//的两步全部向下或者向右
                    v=max(v,f[k-1][i1][i2]+t);//或者一个向右一个向下                    
                }

            }
        }
    }
    cout<<f[n+n][n][n]<<endl;
    return 0; 
}

 这道题和上一题思路基本一样,

本题是不能走相同的点,而上一题是走到相同的点时,只加一次权值

我们可以证明,上一题的最优的两条路线是可以不重合,因为

 当c点为两条最优路线的交点时,Wa和Wb肯定是0,否则绝对会有一条路线通过他们,因为如果相交走的话,c点的权值只会加一次,所以Wa和Wb肯定是0。

那么我们就可以把两天路线的改变一下,并且最终的最大值不变,而且两条路现还不相交。那么就可以用当前这个思路来做本题。

#include<iostream>

using namespace std;

const int N = 60;
int w[N][N];
int f[N*2][N][N];


int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&w[i][j]);
            
    for(int k=2;k<=n+m;k++)
    {
        for(int i1=1;i1<=n;i1++)
        {
            for(int i2=1;i2<=n;i2++)
            {
                int j1=k-i1,j2=k-i2;
                if(j1>=1&&j1<=m&&j2>=1&&j2<=m)
                {
                    int t=w[i1][j1];
                    if(i1!=i2) t+=w[i2][j2];
                    
                    int &v=f[k][i1][i2];
                    v=max(v,f[k-1][i1-1][i2-1]+t);
                    v=max(v,f[k-1][i1-1][i2]+t);
                    v=max(v,f[k-1][i1][i2-1]+t);
                    v=max(v,f[k-1][i1][i2]+t);
                }
            }
        }
    }
    
    cout<<f[n+m][n][n]<<endl;
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值