输出包括两行,第一行一个整数n,代表数组arr长度,第二行包含n个整数,第i个代表arr[i]
。
输出一个整数,代表最后获胜者的分数。
4 1 2 100 4
101
时间复杂度,空间复杂度
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
String[] strCards = br.readLine().split(" ");
int[] cards = new int[n];
for(int i = 0; i < n; i++) cards[i] = Integer.parseInt(strCards[i]);
System.out.println(first(cards, 0, cards.length - 1)); // 假设A玩家先,并让他获胜
}
// 先手函数
private static int first(int[] cards, int left, int right) {
if(left == right) return cards[left]; // 剩最后一张牌,拿走
// 先手利益最大化
return Math.max(cards[left] + second(cards, left + 1, right), cards[right] + second(cards, left, right - 1));
}
// 后手函数
private static int second(int[] cards, int left, int right) {
if(left == right) return 0; // 剩最后一张牌,被先手的拿了
return Math.min(first(cards, left + 1, right), first(cards, left, right - 1)); // 先手留最少的给后手
}
} 然后根据递归的依赖关系改出动规版本:(1)有两个递归函数,就有两张动态规划表;(2)对于区间[left,right]上面的结果,dp[left][right]依赖left+1和right-1,因此left从大往小遍历,right从小往大遍历;(3)left不能大于right,因此动态规划表中left>right的区域无效。 import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
String[] strCards = br.readLine().split(" ");
int[] cards = new int[n];
for(int i = 0; i < n; i++) cards[i] = Integer.parseInt(strCards[i]);
// 先手和后手一起动规
int[][] dpFirst = new int[n][n];
int[][] dpSecond = new int[n][n];
for(int right = 0; right < n; right ++){
for(int left = right; left >= 0; left --){
if(left == right){
// 只剩一张牌,先手的拿
dpFirst[left][right] = cards[left];
dpSecond[left][right] = 0;
}else if(left < right){
dpFirst[left][right] = Math.max(cards[left] + dpSecond[left + 1][right], cards[right] + dpSecond[left][right - 1]);
dpSecond[left][right] = Math.min(dpFirst[left + 1][right], dpFirst[left][right - 1]);
}
}
}
System.out.println(Math.max(dpFirst[0][n - 1], dpSecond[0][n - 1]));
}
} //一般的递归法和动态规划方法,左神的书已经讲的比较清楚
//这里主要说一说另一种思路
//设胜者的总分为x,败者的总分为y,且有 x - y = diff; //方程一
//又因为两者的分数和为纸牌的总分,则有 x + y = sum; //方程二
//联立方程式可得 x = (sum + diff)/2;
//因此题目就转化为求两者的总分差diff
//令递推公式f(i,j):在剩余的i~j牌中,A(先拿)的分数减去B(后拿)的分数
//因此 f(i,j)=max(arr[i]-f(i+1,j),arr[j]-f(i,j-1));
//上式中的f(i+1,j)为剩余牌中B的分数减去A的分数,加负号并加上arr[i],
//代表A取最左边牌的情况,arr[j]-f(i,j-1)的含义为取最右的情况
//根据递推公式直接递归的方法
//diff = first - second
int getDiffCore(const int *arr, int i, int j);
int winner_Solution3_Recursive(const int arr[], const int len)
{
if (arr == NULL || len < 1)
return 0;
int sum = 0;
for (int i = 0; i < len; ++i)
sum += arr[i];
int diff = getDiffCore(arr, 0, len - 1);
if (diff < 0)
diff = -diff;
return (sum + diff) / 2;
}
int getDiffCore(const int *arr, int i, int j)
{
if (i == j)
return arr[i];
return std::max(arr[i] - getDiffCore(arr, i + 1, j), arr[j] - getDiffCore(arr, i, j - 1));
}
//===================================
//一般的动态规划
int winner_Solution3(const int arr[], const int len)
{
if (arr == NULL || len < 1)
return 0;
int sum = 0;
for (int i = 0; i < len; ++i)
sum += arr[i];
int **f = make2DArray<int>(len, len);
for (int j = 0; j < len; ++j)
{
f[j][j] = arr[j];
for (int i = j - 1; i >= 0; --i)
{
f[i][j] = std::max(arr[i] - f[i + 1][j], arr[j] - f[i][j - 1]);
}
}
int diff = f[0][len - 1];
if (diff < 0)
diff = -diff;
return (sum + diff) / 2;
}
//================================
//空间压缩后,空间复杂度为O(N)
int winner_Solution3(const int arr[], const int len)
{
if (arr == NULL || len < 1)
return 0;
int sum = 0;
for (int i = 0; i < len; ++i)
sum += arr[i];
int *dp = new int[len];
for (int i = len - 1; i >= 0; --i)
{
dp[i] = arr[i];
for (int j = i + 1; j < len; ++j)
{
dp[j] = std::max(arr[i] - dp[j], arr[j] - dp[j - 1]);
}
}
int diff = dp[len - 1];
if (diff < 0)
diff = -diff;
return (sum + diff) / 2;
}
#include <bits/stdc++.h> using namespace std; int win(vector<int> arr, int n){ vector<int> f(n,0); vector<int> s(n,0); for(int j=0; j<n; j++){ f[j] = arr[j]; s[j] = 0; for(int i=j-1; i>=0; i--){ int k=j, a=f[i]; f[i] = max(arr[i]+s[i+1], arr[k--]+s[i]); //在纸上画下就知道 s[i] = min(f[i+1], a); } } return max(f[0], s[0]); } int main(){ int n; scanf("%d", &n); if(n == 0) return 0; vector<int> arr(n); for(int i=0; i<n; i++) scanf("%d", &arr[i]); cout << win(arr, n); return 0; }
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, s=0;
cin>>n;
int a[n], dp[n];
for(int i=0;i<n;i++){
cin>>a[i];
dp[i] = a[i];
s += a[i];
}
for(int j=1;j<n;j++)
for(int i=0;i<n-j;i++)
dp[i] = max(a[i]-dp[i+1], a[i+j]-dp[i]);
cout<<(s+abs(dp[0]))/2<<endl;
return 0;
} n = int(input())
arr = list(map(int,input().split(' ')))
def win2(arr,n):
if not arr&nbs***bsp;len(arr)==0:
return 0
f = [[0] * n] * n
s = [[0] * n] * n
for j in range(n):
f[j][j] == arr[j]
for i in range(j-1,-1,-1):
f[i][j] = max(arr[i]+s[i+1][j], arr[j] + s[i][j-1])
s[i][j] = min(f[i+1][j], f[i][j-1])
return max(f[0][n-1] , s[0][n-1])
ans = win2(arr,n)
print(ans)
# 这题python跑不通嘛? 是O(N^2)也通不过。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
int[][] dpf = new int[n][n];
int[][] dps = new int[n][n];
for (int j = 0; j < n; j++) {
for (int i = n - 1; i >= 0; i--) {
if (i > j) {
continue;
} else if (i == j) {
dpf[i][j] = arr[i];
dps[i][j] = 0;
} else {
dpf[i][j] = Math.max(arr[i] + dps[i + 1][j], arr[j] + dps[i][j - 1]);
dps[i][j] = Math.min(dpf[i + 1][j], dpf[i][j - 1]);
}
}
}
int res = Math.max(dpf[0][n - 1], dps[0][n - 1]);
System.out.println(res);
}
}
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int[] arr=new int[n];
for(int i=0;i<n;i++){
arr[i]=sc.nextInt();
}
System.out.print(win(n,arr));
}
public static int win(int n,int[] arr){
if(arr==null||n==0){
return 0;
}
int[][] f=new int[n][n];
int[][] s=new int[n][n];
for(int j=0;j<n;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 Math.max(f[0][n-1],s[0][n-1]);
}
} #include <iostream>
using namespace std;
#define N 5000
int arr[N];
int f[N][N];
int g[N][N];
int max2(int a,int b)
{
return (a>b? a:b);
}
int min2(int a,int b)
{
return (a<b? a:b);
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;++i)
{
cin>>arr[i];
}
for(int i=0;i<n;++i)
{
f[i][i]=arr[i];
g[i][i]=0;
}
// dp process
for(int len=1;len<n;++len)
{
for(int i=0;i+len<n;++i)
{
f[i][i+len]=max2(arr[i]+g[i+1][i+len],arr[i+len]+g[i][i+len-1]);
g[i][i+len]=min2(f[i+1][i+len],f[i][i+len-1]);
}
}
cout<<max2(f[0][n-1],g[0][n-1])<<endl;
return 0;
} import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();
}
int[][] f = new int[n][n];
int[][] s = new int[n][n];
for (int i = 0; i < n; i++) {
f[i][i] = a[i];
s[i][i] = 0;
}
for (int d = 1; d < n; d++) {
for (int i = 0; i < n - d; i++) {
f[i][i + d] = Math.max(a[i] + s[i + 1][i + d], a[i + d] + s[i][i + d - 1]);
s[i][i + d] = Math.min(f[i + 1][i + d], f[i][i + d -1]);
}
}
System.out.println(Math.max(f[0][n-1], s[0][n-1]));
}
}