算法训练 方格取数 蓝桥杯

问题描述
  设有N*N的方格图(N<=10),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。
  某人从图的左上角的A 点(1,1)出发,可以向下行走,也可以向右走,直到到达右下角的B点(N,N)。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
  此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。
输入格式
  输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。
输出格式
  只需输出一个整数,表示2条路径上取得的最大的和。
样例输入
  8
  2 3 13
  2 6 6
  3 5 7
  4 4 14
  5 2 21
  5 6 4
  6 3 15
  7 2 14
  0 0 0
样例输出
  67


思路

一个人走两次可以看做两个人同时走,这里有两个要点:

x1+y1=x2+y2 也就是说这两人并排在一条斜线

为了和最大,两人除了开头结尾,不能走过同一个格子上


蓝桥oj最后一个测试数据貌似有问题;锦囊里的那个递推式不符合最优子结构,因为F(i-1,j,k'')不是最大,但是两个V值足够大,也能得到最优解

#include<stdio.h>
#define max2(a,b) a>b?a:b
#define min2(a,b) a<b?a:b
int a[100][100]={0};//储存表格
int N;
int main(){
int x,y,i,j,k,q,t,max,min,x1,x2;
int dp[20][20][20][20]={0};//储存从两点到终点的路径经过的数值和的最大值
int yb[2],yc[2],xb[2],xc[2];
scanf("%d",&N);
while(1){
    scanf("%d%d",&x,&y);
    scanf("%d",&a[x][y]);
    if(x==0&&y==0&&a[x][y]==0)
        break;
}
dp[N][N][N][N]=a[N][N];
for(i=2*N-1;i>=2;i--){//两点总在同一直线上,i=x+y,把表格看作一条一条斜线
    max=min2(N,i-1);
    min=max2(1,i-N);
    for(x1=min;x1<=max;x1++){
        for(x2=min;x2<=max;x2++){//遍历在这条斜线上,两个点的任意组合
            if(x1==x2&&!(x1==1&&x2==1))continue;
            yb[0]=i-x1+1;
            yb[1]=i-x1;
            xb[0]=x1;
            xb[1]=x1+1;
            yc[0]=i-x2+1;
            yc[1]=i-x2;
            xc[0]=x2;
            xc[1]=x2+1;
            q=0;
            for(j=0;j<=1;j++){
                for(k=0;k<=1;k++){
                if(xb[j]==xc[k])continue;//同一直线,x不同,就不会重叠
                if(q<(t=a[x1][i-x1]+a[x2][i-x2]+dp[xb[j]][yb[j]][xc[k]][yc[k]])){
                   q=t;
                   }
                }
            }
        dp[x1][i-x1][x2][i-x2]=q;
        }
    }
}
dp[1][1][1][1]-=a[1][1];
printf("%d",dp[1][1][1][1]);
return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值