从数组两头抽取元素游戏

给定一个数组,玩家A,B每次从数组头或尾取数,且只能从头尾取。假定A,B都绝顶聪明,均采取最优策略,判断A先手的情况下,A是否能够获胜。

分析:  f(i, j) 表示 在arr[i~j]中A 先手时能够获得的最大分数,s(i, j) 表示 A后手时能够获得的最大分数。

首先分析f(i, j)。 A可先取arr[i], 取完后剩余arr[i+1, j]。此时相当于A后手在[i+1, j]的情况了。

也可先取arr[j], 取完后剩余arr[i, j - 1]。 此时相当于A后手在[i, j -1]的情况了。

则 f(i, j) = max{arr[i] + s(i+1, j), arr[j] + s(i, j-1)}

再分析s(i, j)。B可先取arr[i] 或 arr[j] 。取完后相当于A先手的情况了。只是在这种情况下,B会留下最差解。

s(i, j) = min{arr[i] + f(i+1, j), arr[j] + f(i, j-1)};

故可生成两个二维矩阵。代码如下:

边界条件:

f[j][j] = arr[j]; 因为只有一个数,先手必取这个数。
public static int win2(int[] arr) {
		if (arr == null || arr.length == 0) {
			return 0;
		}
		int[][] f = new int[arr.length][arr.length];
		int[][] s = new int[arr.length][arr.length];
		for (int j = 0; j < arr.length; j++) {
			f[j][j] = arr[j];
			for (int i = j - 1; i >= 0; i--) {
				f[i][j] = Math.max(arr[i] + s[i + 1][j], arr[j] + s[i][j - 1]);
				s[i][j] = Math.min(f[i + 1][j], f[i][j - 1]);
			}
		}
		return f[0][arr.length - 1], s[0][arr.length - 1];
	}

  

上述方法时间复杂度O(N2),用到了两个二维数组。可以在空间复杂度上稍微优化一下,只使用1个二维数组。

用dp[i][j]表示在arr[i~j]中A先手的情况能取得的最大分数。则A的这一次先手与下一次先手有4种可能:

1. A  取 arr[i],      B 取 arr[j]   ,  剩下[i+1, j-1]

2. A  取 arr[i],    B 取arr[i+1],  剩下[i+2, j]

3. A  取 arr[j],    B 取arr[i],      剩下[i+1, j-1]

4. A  取arr[j] ,    B 取arr[j-1],   剩下[i, j-2]

前两种情况取最小情况,后两种情况取最小情况,然后取最大值。其实就是综合之前的情况。

边界条件:

i == j时,就是取arr[i]; 同时,此种情况必须保证j >= i +2, 即至少有3个数。代码如下:

public  static int win1(int[] arr){
		if(arr == null || arr.length == 0)
			return 0;

		int len = arr.length;
		int[][] dp = new int[len][len];
		int part1, part2, part3, part4;

		for(int i = 0; i < len; i++)
			dp[i][i] = arr[i];

		for(int i = len - 1; i >= 0; i--)
			for(int j = i+1; j < len; j++){
				if( j >= i+2 ){
					part1 = ( i <= len -3 ? (arr[i] + dp[i+2][j]) : 0 );
					part2 =  ((i <= len -2 && j >= 1) ? (arr[i] +dp[i+1][j]) : 0);
					part3 = (j >= 2 ? (arr[j] + dp[i][j-2]) : 0);
					part4 =  ((j >= 1 && i <= len-2) ? (arr[j] + dp[i+1][j-1]) : 0);

					dp[i][j] = Math.max(Math.min(part1, part2), Math.min(part3, part4));
				}else
					dp[i][j] = Math.max(arr[i], arr[j]);
			}

		return dp[0][len-1];
	}

  

时间: 2024-10-29 04:33:48

从数组两头抽取元素游戏的相关文章

qsort 函数的使用——对普通数组、指针数组、二维数组中的元素进行排序

在ANSI C中,qsort函数的原型是 #include <stdlib.h> void qsort(void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *)); 解释:qsort函数对含有nmemb个元素的数组进行排序,而base指针指向数组的第一个元素.这个数组的元素个数由size指定. compar函数对qsort的比较操作进行定义,所以可以定制数字的比较,字符串的比较,甚至结构体

用for循环将数组里的元素排序

#include<stdio.h>int  main() //定义数组的容量# define SIZE 6{ unsigned int i,j,temp;//定义要用的相关变量int a[SIZE]={12,45,14,96,56,23};printf("冒泡排序前:");for(i=0;i<SIZE;i++)//for循环输出排序前数组里的元素{printf("%d",a[i]); } //计算机内部进行排序操作 for(i=0;i<SIZ

写一个函数实现数组中的元素随机乱序排序

//原生JS写一个函数实现一个shuffle方法,将数组中的元素随机乱序排序 var shuffle = function(arr){ var len,t,rand; for(var i =0;len = arr.length,i<len;i++){ rand = parseInt(Math.random()*len);//parseInt(Math.random()*(len-1-0)+1);或者rand = Math.floor(Math.random()*(len-1-0)+1);即Mat

数组-06. 找出不是两个数组共有的元素

数组-06. 找出不是两个数组共有的元素(20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 张彤彧(浙江大学) 给定两个整型数组,本题要求找出不是两者共有的元素. 输入格式: 输入分别在2行中给出2个整型数组,每行先给出正整数N(<=20),随后是N个整数,其间以空格分隔. 输出格式: 在一行中按照数字给出的顺序输出不是两数组共有的元素,数字间以空格分隔,但行末不得有多余的空格.题目保证至少存在一个这样的数字.同一数字不重复

java 数组比较,元素的比较,Comparable,Comparator比较的应用实现,排序,查找示例

java 数组比较,元素的比较,自定义Comparator的实现,排序,查找示例 package org.rui.array.compar; import java.util.Arrays; import java.util.Random; import org.rui.generics.anonymity.Generator; /** * 程序设计的基本目标是"将保持不变的事物与会发生改变的事物相分离" * 而这是,不变的是通用的排序算法,变化的是各种对象相互比较的方式, * 因此,

统计数组中重复元素个数

/** * 循环统计数组或集合中的重复元素个数 * @param args */ public static void main(String[] args) { Map<String, Integer> map = new HashMap<String, Integer>(); String[] ss = {"白","黑","绿","白"}; for (int i = 0; i < ss.len

Substring with Concatenation of All Words, 返回字符串中包含字符串数组所有字符串元素连接而成的字串的位置

问题描述:给定一个字符数组words,和字符串s,返回字符数组中所有字符元素组成的子串在字符串中的位置,要求所有的字符串数组里的元素只在字符串s中存在一次. 算法分析:这道题和strStr很类似.只不过strStr是子串,而这个题是字符串数组里的元素组成的子串,字符串数组里的元素是无序的,但是必须全部包含.所有考虑使用map集合.关键点在于几个临界值,字符串元素在s中重复了怎么做,找到一个符合的子串后怎么做,有字符串元素不匹配怎做. import java.util.ArrayList; imp

删除数组中某个元素

需求:已知一个数组,删除其中某个元素,其它向左移,最后一位补null值 分析: 1.找出要删除元素的下标,找个变量接收 2.此位置元素后面的元素依次向左移一位 3.补齐最后一位赋值null 4.输出新数组 /** * */ package com.cn.u4; /** * @author Administrator *删除数组中某个元素值 */ public class DelArray { public static void main(String[] args) { //定义数组 Stri

去掉数组重复的元素

问题描述 输入10个整数组成的序列,要求对其进行升序排序,并去掉重复元素.输入格式 10个整数.输出格式 多行输出,每行一个元素.样例输入2 2 3 3 1 1 5 5 5 5样例输出123 5 代码: import java.util.*;public class Shuzupaixuchuchong {    public static void fun(int arr[])    {          int length=arr.length;         // 共有3个for循环