BZOJ 2101 [Usaco2010 Dec]Treasure Chest 藏宝箱:区间dp 博弈【两种表示方法】【压维】

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2101

题意:

  共有n枚金币,第i枚金币的价值是w[i]。

  把金币排成一条直线,Bessie和Bonny轮流取金币,看谁取到的钱最多。

  Bessie先取,每次只能取一枚金币,而且只能选择取直线两头的金币,不能取走中间的金币。当所有金币取完之后,游戏就结束了。

  Bessie和Bonny都是非常聪明的,她们会采用最好的办法让自己取到的金币最多。

  请帮助Bessie计算一下,她能拿到多少钱?

 

题解:

  区间dp共有两种表示状态的方法:

    (1)dp[i][j]:表示区间[i,j]的答案。

      一般转移为:dp[i][j] = best(dp[i+1][j], dp[i][j-1])

 

    (2)dp[i][j]:左端点为i,区间长度为j。

      一般转移为:dp[i][j] = best(dp[i][j-1], dp[i+1][j-1])

  显然,第二种是可以压维的。因为dp[i][j]只与dp[...][j-1]有关。

  在此题中,第一种表示会炸空间,所以只能用第二种。

 

  表示状态:

    dp[i][j] = max wealth

    i:起点为i

    j:区间长度为j

    表示对于当前区间,先手的最大获利。

 

  找出答案:

    ans = dp[1][n]

    表示整个区间。

 

  如何转移:

    对于一个区间,这个区间内的价值总和是一定的。

    那么如果要让自己获利更大,就是要让对方接下来的获利最小。

    自己的获利 = 区间价值总和 - 对方获利

    即:dp[i][j] = sum(i,i+j-1) - min(dp[i][j-1], dp[i+1][j-1])

 

  边界条件:

    dp[i][1] = w[i]

    只能拿走剩下的一个硬币。

 

  优化:

    压维。

    前缀和。

 

AC Code:

 1 // state expression:
 2 // dp[i][j] = max wealth
 3 // i: start pos
 4 // j: len of present section
 5 //
 6 // find the answer:
 7 // dp[1][n]
 8 //
 9 // transferring:
10 // dp[i][j] = sum(i,i+j-1) - min(dp[i][j-1], dp[i+1][j-1])
11 //
12 // boundary:
13 // dp[i][1] = w[i]
14 #include <iostream>
15 #include <stdio.h>
16 #include <string.h>
17 #define MAX_N 5005
18 
19 using namespace std;
20 
21 int n;
22 int w[MAX_N];
23 int dp[MAX_N];
24 int sum[MAX_N];
25 
26 void read()
27 {
28     cin>>n;
29     for(int i=1;i<=n;i++)
30     {
31         cin>>w[i];
32     }
33 }
34 
35 void cal_sum()
36 {
37     sum[0]=0;
38     for(int i=1;i<=n;i++)
39     {
40         sum[i]=sum[i-1]+w[i];
41     }
42 }
43 
44 void solve()
45 {
46     cal_sum();
47     for(int j=1;j<=n;j++)
48     {
49         for(int i=1;i<=n;i++)
50         {
51             if(j==1) dp[i]=w[i];
52             else dp[i]=sum[i+j-1]-sum[i-1]-min(dp[i],dp[i+1]);
53         }
54     }
55 }
56 
57 void print()
58 {
59     cout<<dp[1]<<endl;
60 }
61 
62 int main()
63 {
64     read();
65     solve();
66     print();
67 }

 

posted @ 2017-10-05 19:41  Leohh  阅读(244)  评论(0编辑  收藏  举报