zoukankan      html  css  js  c++  java
  • UVA 10891 Game of Sum DP

    题意:

    给n个数,A,B两人轮流取,每次可从左右其中一边取1或多个数,两个人都尽量使自己取的数总和最大,问最终sumA-sumB最大为多少。

    由于两个人取的数总和是一定的,所以只要求出先取的那个最多有多少就行了。

    用dp[i][j]表示a[i..j]这一段数中先取的人能取到的最大和。(这里的先取意思是表示这在一段先取,不是A的意思)

    先取的人可能取左边任意一段a[i..i],a[i..i+1],a[i...i+2]....a[i,j]或右边任意一段a[j...j],a[j-1...j],a[j-2..j]....a[i,j]

    那么另一个人就有可能从a[i+1...j]、a[i+2....j],a[j..j],0,a[i..i],a[i...i+1],a[i..i+2]...a[i...j-1]中取。0表示已经被取完,也就是边界。

    要让dp[i][j]最大,最要让另一个人从剩下的数中能取到的最大值最小

    dp[i][j]=sum[i][j]-min{ dp[i+1][j] , dp[i+2][j] , ...  dp[j][j] , 0 , dp[i][i+1] , dp[i][i+2] , dp[i][j-1] };

     状态数是n^2,每个状态的转移有2n个,所以总复杂度为O(n^3)对于这题的n<=100的数据量已经足够

    最终的结果就是dp[1][n]-(sum[1][n]-dp[1][n])=2*dp[1][n]-sum[1][n];

    int da[110];
    int sum[110];
    int dp[110][110];
    int vis[110][110];
    int f(int l,int r)
    {
        if(vis[l][r])return dp[l][r];
        vis[l][r]=1;
        int m=0;
        for(int i=l;i<r;i++)
        {
            m=min(m,f(l,i));
        }
        for(int i=r;i>l;i--)
        {
            m=min(m,f(i,r));
        }
        return dp[l][r]=sum[r]-sum[l-1]-m;
    }
    int main()
    {
        int n;
        while(scanf("%d",&n)!=EOF&&n)
        {
            sum[0]=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&da[i]);
                sum[i]=sum[i-1]+da[i];
            }
            memset(vis,0,sizeof(vis));
            printf("%d
    ",2*f(1,n)-sum[n]);
        }
        return 0;
    }
    View Code

    但是还能把状态的转移优化
    设f[i][j]=min{ f[i][k] | i<=k<=j }; g[i][j] = min{ g[k][j] | i<=k<=j };

    那么dp[i][j] = sum[i][j] - min{ f[i][j-1] , g[i+1][j] , 0}

    f[i][j]和g[i][j]也可以同样递推得到

    复杂度便降到O(n^2)

    int da[110];
    int sum[110];
    int dp[110][110];
    int g[110][110];
    int f[110][110];
    int main()
    {
        int n;
        while(scanf("%d",&n)!=EOF&&n)
        {
            sum[0]=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&da[i]);
                sum[i]=sum[i-1]+da[i];
            }
            for(int len=0;len<n;len++)
            {
                for(int i=1;i+len<=n;i++)
                {
                    if(len>0)
                    {
                        int m;
                        int j=i+len;
                        m=min(f[i][j-1],g[i+1][j]);
                        m=min(m,0);
                        dp[i][j]=sum[j]-sum[i-1]-m;
                        f[i][j]=min(f[i][j-1],dp[i][j]);
                        g[i][j]=min(g[i+1][j],dp[i][j]);
                    }
                    else
                    {
                        dp[i][i]=da[i];
                        f[i][i]=da[i];
                        g[i][i]=da[i];
                    }
                }
            }
            printf("%d
    ",2*dp[1][n]-sum[n]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    [刘阳Java]_MyBatis_其他方式来实现多表查询的操作_第9讲
    [刘阳Java]_MyBatis_实体关系映射_第8讲
    [刘阳Java]_MyBatis_动态SQL标签用法_第7讲
    [刘阳Java]_MyBatis_常规标签的用法_第6讲
    nodejs配置nginx 以后链接mongodb数据库
    es6学习
    学生管理系统
    node exprss-session 和connect-mongo
    容错处理try
    node错误中间件处理 express类 带有路由操作
  • 原文地址:https://www.cnblogs.com/BMan/p/3249753.html
Copyright © 2011-2022 走看看