分金子(奇虎360 2017春招真题)题目详解

分金子(奇虎360 2017春招真题)

 

题目详情:http://exercise.acmcoder.com/online/online_judge_ques?ques_id=3863&konwledgeId=42  

 

题目描述  :                                                          

AB两伙马贼意外地在一片沙漠中发现了一处金矿,双方都想独占金矿,但各自的实力都不足以吞下对方,经过谈判后,双方同意用一个公平的方式来处理这片金矿。处理的规则如下:他们把整个金矿分成n段,由AB开始轮流从最左端或最右端占据一段,直到分完为止。 

马贼A想提前知道他们能分到多少金子,因此请你帮忙计算他们最后各自拥有多少金子?(两伙马贼均会采取对己方有利的策略)


该题目的解决需要使用动态规划,以下对动态规划做简单介绍:                                                   

动态规划的主要难点在于理论上的设计,也就是下面4个步骤的确定:

(1)划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。在划分阶段时,注意划分后的阶段一定要是有序的或者是可排序的,否则问题就无法求解。

(2)确定状态和状态变量:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。

(3)确定决策并写出状态转移方程:因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。所以如果确定了决策,状态转移方程也就可写出。但事实上常常是反过来做,根据相邻两个阶段的状态之间的关系来确定决策方法和状态转移方程

(4)寻找边界条件:给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。

一旦设计完成,实现部分就会非常简单。

使用动态规划求解问题,最重要的就是确定动态规划三要素:

(1)问题的阶段 (2)每个阶段的状态

(3)从前一个阶段转化到后一个阶段之间的递推关系。

递推关系必须是从次小的问题开始到较大的问题之间的转化,从这个角度来说,动态规划往往可以用递归程序来实现,不过因为递推可以充分利用前面保存的子问题的解来减少重复计算,所以对于大规模问题来说,有递归不可比拟的优势,这也是动态规划算法的核心之处。

确定了动态规划的这三要素,整个求解过程就可以用一个最优决策表来描述最优决策表是一个二维表,其中行表示决策的阶段,列表示问题状态,表格需要填写的数据一般对应此问题的在某个阶段某个状态下的最优值(如最短路径,最长公共子序列,最大价值等),填表的过程就是根据递推关系,从1行1列开始,以行或者列优先的顺序,依次填写表格,最后根据整个表格的数据通过简单的取舍或者运算求得问题的最优解。

f(n,m)=max{f(n-1,m), f(n-1,m-w[n])+P(n,m)}

 

 

代码和分析如下:

一般情况下,最优决策表中填充的数据是从单一(把AB看作同一个人)角度考虑此问题的最优值,即每一次都是同一个人去选择金矿时的最优值;而实际上在本题目中是A和B交叉去选择,且在选择最优值时,A和B的策略是一样的,所以计算A在某一子问题中的最优值时要相应地减去B在同一子问题中选择的最优值

import java.util.Scanner;
public class Main{
      public static void main(String[] args) {
            Scanner in = new Scanner(System.in);
            int arrayNum = in.nextInt();
            for (int i = 1; i <= arrayNum; i++) {
                int n = in.nextInt();
                int[] a = new int[n+1];
                int[] sum = new int[n+1];
                sum[0]=0;
                for (int j = 1; j < a.length; j++) {
                    a[j] = in.nextInt();
                    sum[j] = sum[j-1]+a[j];
                }
                int maxGold[][] = new int[n+2][n+2];
                for (int j = 0; j < n; j++) {
                    for (int k = 1; k <= n-j; k++) {
                        maxGold[k][j+k] = Math.max(a[k+j]+sum[k+j-1]-sum[k-1]-maxGold[k][j+k-1],a[k]+sum[k+j]-sum[k]-maxGold[k+1][j+k]);
                    }
                }
                System.out.println("Case #" + i + ": " + maxGold[1][n] + " " + (sum[n] - maxGold[1][n]));
            }
      }          
}
 

                                                          

样例n=10金子矿段情况140 649 340 982 105 86 56 610 340 879的解题过程:

maxGold[k][k+j]

0

1

2

3

4

5

6

7

8

9

10

11

0

 

B四阶子问题

A四阶子问题

B三阶子问题

A三阶子问题

B二阶子问题

A二阶子问题

B一阶子问题

A一阶子问题

B的初始问题

A的初始问题

 

1

0

140

649

480

1631

585

1717

641

2327

981

3206

0

2

 

0

649

649

1322

1631

1094

1717

1150

2372

1720

0

3

 

 

0

340

982

445

1068

501

1678

841

2557

0

4

 

 

 

0

982

982

1068

1068

1143

1678

1483

0

5

 

 

 

 

0

105

105

164

696

501

1575

0

6

 

 

 

 

 

0

86

86

666

696

1275

0

7

 

 

 

 

 

 

0

56

610

393

1489

0

8

 

 

 

 

 

 

 

0

610

610

1219

0

9

 

 

 

 

 

 

 

 

0

340

879

0

10

 

 

 

 

 

 

 

 

 

0

879

0

11

 

 

 

 

 

 

 

 

 

 

0

0

 

 
 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值