BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)

时间:2021-03-23 01:21:52


题面

具体分析见 dalao博客

  • 妙就妙在当时,BZOJ 3901 棋盘游戏 (找结论+枚举+贪心) ^ BZOJ 3901 棋盘游戏 (找结论+枚举+贪心) ^ BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)
  • 那么就枚举第BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)行的一半,然后就能得到第BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)整行.因为只要满足上面的结论就一定存在可行方案,所以BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)~BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)的每一行的选择互不影响,所以对于 BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)~BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)每一行枚举BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)还是BZOJ 3901 棋盘游戏 (找结论+枚举+贪心),再对于 BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)~BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)枚举BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)还是选BZOJ 3901 棋盘游戏 (找结论+枚举+贪心),求最大值就行了
  • 时间复杂度为BZOJ 3901 棋盘游戏 (找结论+枚举+贪心)

CODE

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 35;
int n, x, a[MAXN][MAXN];
bool rw[MAXN];
inline int calc(int i, int j, bool k) {
	int res = a[i][j];
	res += (rw[j] ? -a[i+x][j] : a[i+x][j]);
	res += (k ? -a[i][j+x] : a[i][j+x]);
	res += (rw[j]^k^rw[x] ? -a[i+x][j+x] : a[i+x][j+x]);
	return res > 0 ? res : -res; //(i,j)选 0 或者选 1 ,取较优的
}
int main () {
	scanf("%d", &n); x = (n+1)>>1;
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= n; ++j)
			scanf("%d", &a[i][j]);
	int ans = -0x7f7f7f7f;
	for(int s = 0; s < (1<<x); ++s) { //枚举第 x 行的状态
		int sum = 0;
		for(int i = 1; i <= x; ++i)
			if(s&(1<<(i-1))) rw[i] = 1, sum -= a[x][i];
			else rw[i] = 0, sum += a[x][i];
		for(int i = x+1; i <= n; ++i) {
			rw[i] = rw[x] ^ rw[i-x];
			if(rw[i]) sum -= a[x][i];
			else sum += a[x][i];
		}
		for(int i = 1; i < x; ++i) { //每一行考虑
			int tmp0 = a[i][x] + (rw[x] ? -a[i+x][x] : a[i+x][x]); //枚举 (i,x) 选 0
			for(int j = 1; j < x; ++j) tmp0 += calc(i, j, 0); //计算当前最小值
			int tmp1 = -a[i][x] + (rw[x] ? a[i+x][x] : -a[i+x][x]);//枚举 (i,x) 选 1
			for(int j = 1; j < x; ++j) tmp1 += calc(i, j, 1); //计算当前最小值
			sum += (tmp0 > tmp1 ? tmp0 : tmp1); //取较优的
		}
		if(sum > ans) ans = sum;
	}
	printf("%d\n", ans);
}