矩阵游戏java_矩阵取数游戏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

int[] que=new int[m];

BigInteger[][] map=new BigInteger[m+1][m+1];

map[0][0]=new BigInteger("0");

for(int j=0;j

que[j]=input.nextInt();

}

BigInteger number=new BigInteger("2");

BigInteger max=new BigInteger("0");

for(int k=0;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

if(map[m-j][j].compareTo(max)>0){

max=map[m-j][j];

}

}

account=account.add(max);

}

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

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值