POJ 1678

博弈题,使用DP来完成。开始时,我以为可以用极大极小加剪枝可以过,但,TLE。。。

看过一些题解,没看懂,但也由此有了启发:

我们只记录差(初始为0),那为1选的数即为在原差值上加上该数,2选即是减去该数。那么,可以有以下的式子来表达这一过程

ANS=A-B+C-D+E-F;

神奇的事情来了,将式子转换一下ANS=A-(B-(C-(D-(E-F))));把TMP=(B-(C-(D-(E-F))));

很明显,我们得到了一个递归的式子。怎么理解呢?这样想,1选了A之后,即到B选。那么,2肯定希望选择后的TMP(也表示一个差值)最大,使得总的差值最小。那么2选后,1却希望总的差值最大,那么,它也只需使得它选之后的C-(D-(E-F)最大(慢慢分析,你会发现是对的)。这里,很显然有一个无后效性。于是,可以采用记忆化搜索来完成。

妙。。。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 using namespace std;
 5 const int inf=(1<<30);
 6 int num[10010],dp[10010];
 7 int n,A,B;
 8 
 9 int work(int m){
10     if(dp[m]!=-inf)
11     return dp[m];
12     int ans=-inf;
13     for(int i=m+1;i<n;i++){
14         int tmp=num[i]-num[m];
15         if(tmp>B) break;
16         if(tmp>=A&&tmp<=B){
17             ans=max(ans,work(i));
18         }
19     }
20     if(ans==-inf){
21         dp[m]=num[m];
22     }
23     else {
24         dp[m]=num[m]-ans;
25     }
26     return dp[m];
27 }
28 
29 void slove(){
30     int ans=-inf;
31     for(int i=0;i<n;i++){
32         if(num[i]>=A&&num[i]<=B){
33             ans=max(ans,work(i));
34         }
35     }
36     if(ans==-inf)
37     printf("0
");
38     else printf("%d
",ans);
39 }
40 
41 int main(){
42     int T;
43     scanf("%d",&T);
44     while(T--){
45         scanf("%d%d%d",&n,&A,&B);
46         for(int i=0;i<n;i++){
47             dp[i]=-inf;
48             scanf("%d",&num[i]);
49         }
50         sort(num,num+n);
51         slove();
52     }
53     return 0;
54 }
View Code
原文地址:https://www.cnblogs.com/jie-dcai/p/3780865.html