Gym - 102623M(状压dp)

https://codeforces.com/gym/102623/problem/M

#include<cstdio>
#include<bits/stdc++.h>
using namespace std;
#define lbt(x)	((x)&(-x))

typedef long long ll;
int n, m;

char s[33][33];
int stone[33];
int num[1 << 8], zhu[1 << 8];
int dp[33][1 << 8][1 << 8];//dp[row][now][pre]
int route[33][1 << 8][1 << 8];//route[row][now][pre] = prep

//0 not-water
//1 water
int sta[33];

void dfs(int row, int now, int pre) {
	if (row < 2)	return;
	sta[row - 2] = route[row][now][pre];
	dfs(row - 1, pre, sta[row - 2]);
}

int main() {
	memset(dp, -1, sizeof dp);
	scanf("%d %d", &n, &m);
	for (int i = 0; i < n; ++i) {
		scanf("%s", s[i]); stone[i] = 0;
		for (int j = 0; j < m; ++j)	stone[i] = (stone[i] << 1) + (s[i][j] == '.' ? 1 : 0);
	}
	//for (int i = 0; i < n; ++i)	printf("%d %d\n", i, stone[i]);

	int limit = (1 << m) - 1;
	for (int i = 1; i <= limit; ++i)	num[i] = num[i - lbt(i)] + 1;
	for (int i = 0; i <= limit; ++i)	zhu[i] = m - num[i];
	
	if (n == 1) {
		int ans = 0, pos = -1;
		for (int i = 0; i <= limit; ++i) {
			if ((i | stone[0]) > stone[0])	continue;
			if (((i | (i << 1) | (i >> 1)) & (limit & stone[0])) < (limit & stone[0]))	continue;
			if (ans < zhu[i] - zhu[stone[0]]) {
				ans = zhu[i] - zhu[stone[0]];
				pos = i;
			}
		}
		for (int i = 0; i < m; ++i) {
			if (s[0][i] == '#')	printf("#");
			else if (pos & (1 << m - i - 1))	printf("O");
			else printf("X");
		}
		puts("");
		return 0;
	}
	//for (int i = 0; i <= limit; ++i)	printf("%d %d\n", i, zhu[i]);
	for (int i = 0; i <= limit; ++i) {
		if ((i | stone[0]) > stone[0])	continue;
		dp[0][i][0] = zhu[i] - zhu[stone[0]];
	}
	//for (int i = 0; i <= limit; ++i)	printf("%d %d\n", i, dp[0][i][0]); puts("");

	for (int i = 0; i <= limit; ++i) {
		if ((i | stone[1]) > stone[1])	continue;
		//printf("%d\n", i);
		for (int pre = 0; pre <= limit; ++pre) {
			if ((pre | stone[0]) > stone[0])	continue;
			if (((pre | (pre << 1) | (pre >> 1) | i) & (limit & stone[0])) < (limit & stone[0]))	continue;
			if (n == 2)	if (((i | (i << 1) | (i >> 1) | pre) & (limit & stone[n - 1])) < (limit & stone[n - 1]))	continue;
			if (dp[1][i][pre] < dp[0][pre][0] + zhu[i] - zhu[stone[1]]) {
				dp[1][i][pre] = dp[0][pre][0] + zhu[i] - zhu[stone[1]];
			}
		}
	}
	//for (int i = 0; i <= limit; ++i) for(int pre = 0; pre <= limit; ++ pre)	printf("%d %d\n", i, dp[1][i][pre]); 

	for (int i = 2; i < n; ++i) {
		for (int now = 0; now <= limit; ++now) {
			if ((now | stone[i]) > stone[i])	continue;
			for (int pre = 0; pre <= limit; ++pre) {
				if ((pre | stone[i - 1]) > stone[i - 1])	continue;
				for (int prep = 0; prep <= limit; ++prep) {
					if ((prep | stone[i - 2]) > stone[i - 2])	continue;
					if (((pre | (pre << 1) | (pre >> 1) | prep | now) & (limit & stone[i - 1])) < (limit & stone[i - 1]))	continue;
					if (i == n - 1) if (((now | (now << 1) | (now >> 1) | pre) & (limit & stone[i])) < (limit & stone[i]))	continue;
					if (i == 2)	if (((prep | (prep << 1) | (prep >> 1) | pre) & (limit & stone[0])) < (limit & stone[0]))	continue;
					if (dp[i][now][pre] < dp[i - 1][pre][prep] + zhu[now] - zhu[stone[i]]) {
						//printf("%d %d %d %d\n", i, now, pre, prep);
						dp[i][now][pre] = dp[i - 1][pre][prep] + zhu[now] - zhu[stone[i]];
						route[i][now][pre] = prep;
					}
				}
			}
		}
	}

	
	//for(auto &it : l)
	int ans = -1;
	int posnow = -1, pospre = -1;	
	for (int now = 0; now <= limit; ++now) {
		if ((now | stone[n - 1]) > stone[n - 1])	continue;
		for (int pre = 0; pre <= limit; ++pre) {
			if ((pre | stone[n - 2]) > stone[n - 2])	continue;
			if (dp[n - 1][now][pre] > ans) {
				ans = dp[n - 1][now][pre];
				posnow = now, pospre = pre;
			}
		}
	}
	//printf("%d\n", ans);
	sta[n - 1] = posnow; sta[n - 2] = pospre;
	dfs(n - 1, posnow, pospre);
	//for (int i = 0; i < n; ++i)	printf("%d\n", sta[i]);
	for (int i = 0; i < n; ++i) {
		int tmp = sta[i];
		for (int j = 0; j < m; ++j) {
			if (s[i][j] == '#')	printf("#");
			else if (tmp & (1 << m - j - 1))	printf("O");
			else printf("X");
		}
		puts("");
	}
}
posted @ 2020-12-03 21:48  wansheking  阅读(116)  评论(0)    收藏  举报