• uva 10891 Game of Sum(区间dp)


    题目连接:10891 - Game of Sum


    题目大意:有n个数字排成一条直线,然后有两个小伙伴来玩游戏, 每个小伙伴每次可以从两端(左或右)中的任意一端取走一个或若干个数(获得价值为取走数之和), 但是他取走的方式一定要让他在游戏结束时价值尽量的高,最头疼的是两个小伙伴都很聪明,所以每一轮两人都将按照对自己最有利的方法去取数字,请你算一下在游戏结束时,先取数的人价值与后取数人价值之差(不要求绝对值)。


    解题思路:这道题目想了一晚上,死憋着不看题解, 结果写出的代码有点渣,dpx[i][j]表示在当前第i个数到第j个数中先取数的人可以达到的最高价值, dpy[i][j]为后取者最高可以达到的最高值。每次根据传入的参数flag判断是该谁去石子, 通过引用返回最优解。


    注意:数字可以为负数,所以标记的时候要注意, 我是重新开了个数组vis.


    #include <stdio.h>
    #include <string.h>
    const int N = 105;
    const int MAX = -0x3f3f3f3f;
    int n, num[N], sum[N], dpx[N][N], dpy[N][N], vis[N][N];
    
    void search(int a, int b, int& x, int& y, int flag) {
        int &A = dpx[a][b], &B = dpy[a][b];
        if (a + 1 == b)
    	A = num[b], B = 0;
    
        if (!vis[a][b]) {
    	int s, f;
    	A = sum[b] - sum[a], B = 0;
    	for (int i = a + 1; i < b; i++) {
    	    search(i, b, s, f, !flag);
    	    if (flag && f + sum[i] - sum[a] > A)
    		A = f + sum[i] - sum[a], B = s;
    	    else if (!flag && s + sum[i] - sum[a] > A)
    		A = s + sum[i] - sum[a], B = f;
    
    	    search(a, i, s, f, !flag);
    	    if (flag && f + sum[b] - sum[i] > A)
    		A = f + sum[b] - sum[i], B = s;
    	    else if (!flag && s + sum[b] - sum[i] > A)
    		A = s + sum[b] - sum[i], B = f;
    	}
        }
        vis[a][b] = 1;
    
        if (flag)
    	x = B, y = A;
        else
    	x = A, y = B;
    }
    
    void solve() {
        int s, f;
    
        memset(dpx, MAX, sizeof(dpx));
        memset(dpy, MAX, sizeof(dpy));
        memset(vis, 0, sizeof(vis));
    
        search(0, n, s, f, 0);
        printf("%d
    ", s - f);
    }
    
    int main() {
        while (scanf("%d", &n) == 1 && n) {
    	// Read;
    	memset(num, 0, sizeof(num));
    	memset(sum, 0, sizeof(sum));
    	for (int i = 1; i <= n; i++) {
    	    scanf("%d", &num[i]);
    	    sum[i] = sum[i - 1] + num[i];
    	}
    
    	solve();
        }
        return 0;
    }



    参考别人的题解,写了下面这个代码,因为两个小伙伴都是按照对自己最有利的方式取数字,那可以看成是一个过程,而确定区间a 到 b的最优解之后, 用sum(a, b) -  最优解就是后取数字的小伙伴可以取到的价值(只有两个人在玩,不是1拿就是2拿), 后取小伙伴的价值坑定是要尽量小自己拿到的才有可能越大。


    #include <stdio.h>
    #include <string.h>
    const int N = 105;
    const int MAX = 1 << 30;
    int max(int a, int b) { return a > b ? a : b; }
    int min(int a, int b) { return a < b ? a : b; }
    
    int n, dp[N][N], vis[N][N], num[N], sum[N];
    
    void read() {
        memset(dp, 0, sizeof(dp));
        memset(vis, 0, sizeof(vis));
        sum[0] = 0;
    
        for (int i = 1; i <= n; i++) {
    	scanf("%d", &num[i]);
    	sum[i] = sum[i - 1] + num[i];
        }
    }
    
    int solve(int a, int b) {
        if (a >= b)	    return 0;
        if (vis[a][b])   return dp[a][b];
        int ans = -MAX, cnt = b - a;
        vis[a][b] = 1;
        for (int i = 1; i <= cnt; i++)
    	ans = max(ans, sum[b] - sum[a] - min(solve(a + i, b), solve(a, b - i)));
        dp[a][b] = ans;
        return ans;
    }
    
    int main() {
        while (scanf("%d", &n), n) {
    	read();
    	printf("%d
    ", solve(0, n) * 2 - sum[n]);
        }
        return 0;
    }
    



  • 相关阅读:
    How Many Answers Are Wrong
    Agri-Net —poj1258
    食物链
    A Bug's Life
    畅通工程
    Shortest path of the king
    Alex and Number
    KMP
    快速幂
    0x04
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3320288.html
Copyright © 2020-2023  润新知