Game of Sum UVA - 10891(动态规划)

题目链接

https://vjudge.net/problem/UVA-10891

题意

有一个长度为n的整数序列,两个游戏者A和B,A先取数,每次只能从一端开始取连续的任意个数(可以取整个序列)。所以数被取完后,游戏结束。以游戏者取走的数之和作为最终得分,求A的得分减去B的得分后的结果。(每个人采取的策略都是让自己的得分尽量高,且两人都足够聪明)。

分析

先画出状态转移图。
初始状态为 (1,n),表示序列剩余区间为(1,n).A取一次数后的状态有2n-1种,分别是剩余区间为:
(1,1)、(1,2)、(1,3)…(1,n-1);
(2,n)、(3,n)、(4,n) …(n,n);
空。
然后考虑给这些状态赋一个有特殊意义的值。这个值与解题直接相关。
设d(i,j)表示初始状态为(i,j)的情况下先手能取到的所有数之和的最大值。
最后就可以考虑如何实现代码了。
我们可以由上到下的搜索,也就是用记忆化搜索写;
也可以由下及上的写,即递推。
这里采用递推写法:
由叶子结点一层一层往上递推,叶子结点为d(i,i)和空区间,i的取值范围是1~n。上一层就是区间长度为2的状态,再上一层就是区间长度为3的状态,一直往上递推。
最后d(1,n)就是A最终的得分,而总分一共为sum(1,n),所以B的得分就是sum(1,n)-d(1,n).然后相减答案就出来了。

递推版

#include 
#include 
#include 
#define INF 0x3f3f3f3f

using namespace std;

const int maxn=100+10;
int d[maxn][maxn],n,sum[maxn];

int main()
{
    while(~scanf("%d",&n) && n)
    {
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            sum[i]=sum[i-1]+x;
            d[i][i]=x;
        }
        for(int i=2;i<=n;i++)
        {
            for(int j=1;j+i-1<=n;j++)
            {
                int tmp=0;
                for(int k=j;k1;k++)
                    tmp=min(tmp,d[j][k]);

                for(int k=j+1;k<=j+i-1;k++)
                    tmp=min(tmp,d[k][j+i-1]);

                d[j][j+i-1]=sum[j+i-1]-sum[j-1]-tmp;
            }
        }
        int ans=d[1][n]-(sum[n]-d[1][n]);
        printf("%d\n",ans);
    }
    return 0;
}

记忆化搜索版

#include 
#include 
#include 
#define INF 0x3f3f3f3f

using namespace std;

const int maxn=100+10;
int d[maxn][maxn],n,sum[maxn],vis[maxn][maxn];

int dfs(int i,int j)
{
    if(vis[i][j]) return d[i][j];
    int tmp=0;
    for(int k=i;kfor(int k=i+1;k<=j;k++)
        tmp=min(tmp,dfs(k,j));
    vis[i][j]=1;
    d[i][j]=sum[j]-sum[i-1]-tmp;
    return d[i][j];
}

int main()
{
    while(~scanf("%d",&n) && n)
    {
        memset(sum,0,sizeof(sum));
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            sum[i]=sum[i-1]+x;
        }
        dfs(1,n);
        int ans=d[1][n]-(sum[n]-d[1][n]);
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(动态规划)