现在的位置: 首页 > 综合 > 正文

UVA -10891 – Game of Sum

2019年02月23日 ⁄ 综合 ⁄ 共 1835字 ⁄ 字号 评论关闭

题目链接~~>

做题感悟:感觉这题很经典,百度了一下才理解怎么做。

解题思路:      

                  这里设 d( i , j ) 代表原序列的第 i ~ j 个元素组成的序列的子序列,在双方都采取最优策略的情况下,先手得分的最大值。那么,如果先手要获得最大值同时让后手得到最小值,因此: d( i , j ) = sum ( i ,  j )  - min{ d( i+1, j ) , d( i+2 , j ) …… d( j , j ) , d( i , j - 1 ) , d( i , j - 2 ) …… d(i , i ) , 0 }  ,sum( i , j
)  是元素 i 到 j 的数之和,‘ 0 ’ 代表取完所有的数。

                   进一步的优化:d( i , j ) = sum( i , j ) - min { d( i+1 , j ) , d( i + 2 , j ) ……d( j , j ) , d( i , j - 1 ) ,d(i , j - 2 ) ……d( i , i ) , 0 } ,令 f( i, j ) = min{d( i , j ) ,d( i+1 , j ) , d(
i + 2 , j ) ……d( j , j ) },      g( i , j ) = min{ d( i , j - 1 ) , d( i , j - 1 ) , d( i , j - 2 ) …… d(i , i ) } ,则状态转移方程:d( i , j ) = sum ( i , j )  - min{ f( i+1 , j ) ,g( i, j - 1 ) , 0 } ,这里 f , g 也可以快速递推出来:f( i , j ) = min{ d( i , j ) ,f( i + 1 , j
) } , g( i , j ) =min{ d( i , j ) , g( i ,j - 1 ) } .

代码:

#include<stdio.h>
#include<cmath>
#include<string.h>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<stdlib.h>
#define INT long long int
using namespace std ;
const int INF = 99999999 ;
const int MY = 20 + 10 ;
const int MX = 100 + 10 ;
int n ;
int dp[MX][MX],sum[MX] ;
int DP(int x,int y)
{
    if(dp[x][y]!=-1)  return dp[x][y] ;
    int& ans = dp[x][y] ;
    ans=0 ;
    for(int i=x+1 ;i<=y ;i++)
       ans = min(ans,DP(i,y)) ;
    for(int i=x ;i<y ;i++)
       ans = min(ans,DP(x,i)) ;
    ans = sum[y]-sum[x-1]-ans ;
    return ans ;
}
int main()
{
    int x ;
    while(scanf("%d",&n),n)
    {
        sum[0]=0 ;
        for(int i=1 ;i<=n ;i++)
        {
            scanf("%d",&x) ;
            sum[i]=sum[i-1]+x ;
        }
        memset(dp,-1,sizeof(dp)) ;
        cout<<2*DP(1,n)-sum[n]<<endl ;
    }
    return 0 ;
}

优化代码:

#include<stdio.h>
#include<cmath>
#include<string.h>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<stdlib.h>
#define INT __int64
using namespace std ;
const int INF = 99999999 ;
const int MY = 100 + 10 ;
const int MX = (1<<11) + 5 ;
const int mod = 1000000000 + 7 ;
int n ;
int f[MY][MY],g[MY][MY],d[MY][MY],a[MY],S[MY] ;
void DP()
{
    for(int i=1 ;i<=n ;i++)
      f[i][i]=g[i][i]=d[i][i]=a[i] ;
    for(int L=1 ;L<n ;L++)
      for(int i=1 ;i+L<=n ;i++)
      {
          int j = i+L ;
          int m = 0 ;
          m = min(m , f[i+1][j]) ;
          m = min(m , g[i][j-1]) ;
          d[i][j]=S[j] - S[i-1] - m ;
          f[i][j]=min(d[i][j],f[i+1][j]) ;
          g[i][j]=min(d[i][j],g[i][j-1]) ;
      }
      cout<<2*d[1][n]-S[n]<<endl ;
}
int main()
{
    while(scanf("%d",&n),n)
    {
        S[0]=0 ;
        for(int i=1 ;i<=n ;i++)
        {
            scanf("%d",&a[i]) ;
            S[i]=S[i-1]+a[i] ;
        }
        DP() ;
    }
    return 0 ;
}

  

抱歉!评论已关闭.