话不多说,先上题目: 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的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());
}
}