USACO 3.3 游戏

https://www.luogu.org/problemnew/show/P2734

是道好dp,加深了我对区间dp的理解

一开始可以有思路:f[i][j]表示区间i-j内,先手的最大得分

但是转移有困难,因为我在思考第二个人会怎么走

实际上这是没有必要的,动态规划不考虑所有步的细节,而是从前一种状态转移,至于前一种如何,并不关心

考虑到,当f[i][j]的人先手取完之后,剩下的就是第二个人,这是可以把他认为是先手

那么第一个人可能取a[i]或a[j],那剩下的人取的就是f[i + 1][j]或者f[i][j - 1],那么区间i-j的和减第二个人的得分就是第一个人的得分

时间:1.0h

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
inline int read()
{
  int ans = 0,op = 1;
  char ch = getchar();
  while(ch < '0' || ch > '9')
    {
      if(ch == '-') op = -1;
      ch = getchar();
    }
  while(ch >= '0' && ch <= '9')
    {
      (ans *= 10) += ch - '0';
      ch = getchar();
    }
  return ans * op;
}
const int maxn = 105;
int n;
int sum[maxn],a[maxn];
int f[maxn][maxn];
/*int dp(int i,int j)
{
  if(j < i) return 0;
  if(f[i][j]) return f[i][j];
  return f[i][j] = max(sum[j] - sum[i] - dp(i + 1,j),sum[j - 1] - sum[i - 1] - dp(i,j - 1));
  }*/              
int main()
{
  n = read();
  for(int i = 1;i <= n;i++)
    a[i] = read(),f[i][i] = a[i];
  for(int i = 1;i <= n;i++)
    sum[i] = sum[i - 1] + a[i];
  for(int i = n - 1;i >= 1;i--)
    for(int j = i + 1;j <= n;j++)
      f[i][j] = max(sum[j] - sum[i - 1] - f[i + 1][j],sum[j] - sum[i - 1] - f[i][j - 1]);
  printf("%d %d",f[1][n],sum[n] - f[1][n]);
}

猜你喜欢

转载自www.cnblogs.com/LM-LBG/p/10048200.html
3.3