HDU 3883 CS and Sugar

2011 Multi-University Training Contest 5 - Host by BNU

HDU 3883 CS and Sugar (DP)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int n, m;
int map[101][101];
int hash[2][101][101][2];
bool vis[101];
int f[2];

int abs(int a){
	if (a < 0) return -a;
	return a;
}

int main(){
	int i, j, k, t, ii, ans;
	int *p;
	while(scanf("%d%d", &n, &m) != EOF){
		for (i = 1; i <= n; i++)
			for (j = 1; j <= m; j++)
				scanf("%d", &map[i][j]);
		memset(vis, 0, sizeof(vis));
		ans = 0x80000000;
		ii = 0;
		for (i = 1; i <= n; i++){			
			ii = 1 - ii;
			for (j = 1; j <= m; j++){
				// 先手f[i][j][0] = map[i][j] - min{hash[i][j][k][1], k > abs(map[i][j])};
				// 后手f[i][j][1] = map[i][j] - min{hash[i][j][k][0], k > abs(map[i][j])};
				f[0] = f[1] = 0x80000000;
				for (k = 100; k >= 0; k--){
					for (t = 0; t <= 1; t++){
						p = & hash[ii][j][k][t];
						*p = 0x80000000;
						if (!vis[k]) continue;
						//renew hash
						if (i > 1 && *p < hash[1 - ii][j][k][t])
							*p = hash[1 - ii][j][k][t];
						if (j > 1 && *p < hash[ii][j - 1][k][t])
							*p = hash[ii][j - 1][k][t];
					
						if (k <= abs(map[i][j])) continue;
						if (f[1 - t] < *p) f[1 - t] = *p;
					}
				}
				if (f[0] == 0x80000000) f[0] = 0;
				if (f[1] == 0x80000000) f[1] = 0;
				f[0] = map[i][j] - f[0];
				f[1] = map[i][j] - f[1];
				if (ans < f[0]) ans = f[0];
				
				k = abs(map[i][j]);
				if (!vis[k] || hash[ii][j][k][0] < f[0]){
					vis[k] = 1;
					hash[ii][j][k][0] = f[0];
				}
				if (!vis[k] || hash[ii][j][k][1] < f[1]){
					vis[k] = 1;
					hash[ii][j][k][1] = f[1];
				}
			}
		}
		printf("%d\n", ans);
	}
    system("pause");
    return 0;
}

/*****************
题意:
n*m方格,格中有数(-100..100),双方轮流取数,要求后者取的位置必须在前者的左上方,且数的绝对值要大于前者。先手可以随意挑位置开始,双方都以最优策略取数,问先手-后手最大差值。

分析:
开始方程错了,由于是博弈,双方都要求最优,所以一旦选择了某点,掌控权就在对方手里,应该以对方利益最大做选择。
f[i][j][0] 先手取(i,j)时可得最大差
f[i][j][1] 后手...
f[i][j][0] = map[i][j] - max{f[i1][j1][1],i1 = 1..i, j1 = 1..j} 注意不是min,要以对方利益最大化考虑
f[i][j][1] = map[i][j] - max{f[i1][j1][0]}
(条件abs(map[i][j]) < abs(map[i1][j1]))
由于转移是O(n^2)的,会超时,故要优化。
注意到每次取最大值,而每个数的绝对值范围[0,100],故记录
hash[i][j][k][0] 先手在(i,j)时,后手可取到的点中,绝对值为k的,最大差值
hash[i][j][k][1] 后手...........先手..................
这样方程
f[i][j][0] = map[i][j] - max{hash[i][j][k][1], k = 0..100}
f[i][j][1] = map[i][j] - max{hash[i][j][k][0], k = 0..100}
转移是O(100),总是O(n^3),n <= 100
当然空间实际可以节省很多,比如f数组没必要开,hash可以滚动之类的
最后交了一次TLE,改了下滚动数组为非取模的
WA,其实是循环体没加大括号...改后
TLE,用C++再交,AC,500ms;用G++再交,50%概率卡过...
*****************/

你可能感兴趣的:(HDU 3883 CS and Sugar)