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%概率卡过...
*****************/