分金子

题目

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

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

输入

测试数据包含多组输入数据。输入数据的第一行为一个正整数T(T<=20),表示测试数据的组数。然后是T组测试数据,每组测试数据的第一行包含一个整数n,下一行包含n个数(n <= 500 ),表示每段金矿的含金量,保证其数值大小不超过1000。

输出

对于每一组测试数据,输出一行"Case #id: sc1 sc2",表示第id组数据时马贼A分到金子数量为sc1,马贼B分到金子数量为sc2。详见样例。

样例输入

2

6

4 7 2 9 5 2

10

140 649 340 982 105 86 56 610 340 879

样例输出

Case #1: 18 11

Case #2: 3206 981

思路

参考博客:传送门

分析可知采用动态规划的思想,每次拿取从整体考虑,且存在最优子结构

令a?表示序列中的第一个或最后一个值、f[i][j]表示从第i个到第j个拿取的最大金子数、sum[i][j]表示从第i个到第j个金子总和
如果先手拿走ai(第一个),那么先手最大的金子数即为
f[i][j] = i + (sum[i+1][j] - f[i+1][j]) 即 f[i][j] = sum[i][j] - f[i+1][j]
如果先手拿走aj(最后一个),那么先手最大的金子数即为
f[i][j] = aj + (sum[i][j-1] - f[i][j-1]) 即 f[i][j] = sum[i][j] - f[i][j-1]
总结为:f[i][j] = sum[i][j] - min(f[i+1][j], f[i][j-1])
其中sum数组可以简化为一维差运算得到,代码中的arr即为f数组

import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		
		int t = cin.nextInt();
		int u = 0;
		while(u < t){
			u ++;
			//f(i, j) = sum(i, j) - min{f(i + 1, j), f(i, j - 1)}
			int n = cin.nextInt();
			int[] sum = new int[505];
			int[][] arr = new int[505][505];
			for(int i=1; i<=n; i++){
				arr[i][i] = cin.nextInt();
				sum[i] = sum[i-1] + arr[i][i];
			}
			
			for(int i=n; i>=1; i--){
				for(int j=i+1; j<=n; j++){
					arr[i][j] = (sum[j] - sum[i-1]) - Math.min(arr[i+1][j], arr[i][j-1]); 
				}
			}
			
			System.out.printf("Case #"+u+": "+arr[1][n]+" "+(sum[n] - arr[1][n])+"\n");
		}
		cin.close();
	}
}

如有错误或不合理的地方,敬请指正~

加油!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值