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\n"); 38 else printf("%d\n",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 }