矩阵取数游戏JAVA题解

  话不多说,先上题目: 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的nm的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下: {C}1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素; {C}2. 每次取走的各个元素只能是该元素所在行的行首或行尾; {C}3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值2i,其中i表示第i次取数(从1开始编号); {C}4. 游戏结束总得分为m次取数得分之和。 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

样例1:

2 3 1 2 3 3 4 2 样例2:

1 4 4 5 0 5 样例3:

2 10 96 56 54 46 86 12 23 88 80 43 16 95 18 29 30 53 88 83 64 67 样例1: 82 样例2: 122 样例3: 316994 【输入输出样例1解释】 第1次:第1行取行首元素,第2行取行尾元素,本次得分为121+221=6 第2次:两行均取行首元素,本次得分为222+322=20 第3次:得分为323+423=56。总得分为6+20+56=82 【限制】 60%的数据满足:1<=n, m<=30, 答案不超过1016 100%的数据满足:1<=n, m<=80, 0<=aij<=1000

这就是NOIP2007T3的题目,这里我给出一个JAVA的解法,至于为什么选择JAVA因为这一题涉及大数运算,使用JAVA能减少很多的工程。

好了,废话不多说,先讲讲我的思路: 首先我们从题目可以知道,所谓的矩阵取数说白了就是求每一个行的最佳取数方法,那么要解决的问题就简化为一个双端队列的取数问题了。我们知道,每取完一个数以后,队列就会变成一个新的双端队列,而且无论你的取数顺序如何,最终还是需要相同的取数步数,因此这是个dp问题,而这题的核心思想即使对于同一个子队列,接下来的操作不会受到之前的操作的影响,于是我们只要保证我们找到生成这个子队列的最优解法就行了。于是我在这里用了一个矩阵来表示取数的结果,k表示取数的步数,当从前端取数的时候则往矩阵下边走,当从后端取数的时候则往右边走,若遇到走入同一个空格的情况则取其最大值,于是当走完m步以后,则会出现一个对角线型的结果图,只要沿着对角线找出最大值输出来即为题解了。

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
    static int m;
    static int n;


    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);


        BigInteger account=new BigInteger("0");


        n=input.nextInt();
        m=input.nextInt();


        for(int i=0;i<n;i++){
            int[] que=new int[m];
            BigInteger[][] map=new BigInteger[m+1][m+1];
            map[0][0]=new BigInteger("0");
            for(int j=0;j<m;j++){
                que[j]=input.nextInt();
            }


            BigInteger number=new BigInteger("2");


            BigInteger max=new BigInteger("0");


            for(int k=0;k<m;k++){
                for(int j=0;j<=k;j++){
                    BigInteger integer1=number.multiply(new BigInteger(""+que[k-j]));
                    BigInteger integer2=number.multiply(new BigInteger(""+que[m-j-1]));
                    integer1=integer1.add(map[k-j][j]);
                    integer2=integer2.add(map[k-j][j]);
                    if(map[k-j+1][j]==null||integer1.compareTo(map[k-j+1][j])>0) {
                        map[k-j+1][j] = integer1;
                    }
                    if(map[k-j][j+1]==null||integer2.compareTo(map[k-j][j+1])>0){
                        map[k-j][j+1]=integer2;
                    }
                }
                number=number.multiply(new BigInteger("2"));
            }


            for(int j=0;j<m;j++){
                if(map[m-j][j].compareTo(max)>0){
                    max=map[m-j][j];
                }
            }


            account=account.add(max);
        }


        System.out.println(account.toString());
    }
}

转载于:https://my.oschina.net/FacelessVoidFV/blog/803604

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值