算法刷题记录(Day 50)

Mondriaan’s Dream(poj 2411)

原题链接
思考过程:
如何去定义状态->0代表的是没有突出去,1代表的是突出去了,对于前一列的一种状态,后一列会有很多中填充的方式,这是乘的一个过程。-最终的结果是要取最后一列全为0的情况。

转化思路,将dp[i][j]用于表示第i列状态为j的取值情况(注意限制在了第i列,即不能突出到第j列),j的二进制为全1时才是填满的状态。
怎么状态转移呢?->可以预先处理出[1<<11][1<<11]的矩阵么?

如果可以的话,外层循环为列数,次内层为状态数,最内层也为状态数,O(1120482048)->很有可能超时

而且如何进行[1<<11][1<<11]的预先处理呢?
先把前面的一行填满,还是竖着的问题->选多个两个??预处理出所有的可能的情况,再进行比对?->超时了

#include
#include
#include
using namespace std;
#define HWMAX 12
int h, w;
vector<int > mould;
long long dp[HWMAX][1 << HWMAX];
void dfs(int lot, int value, int con) {
	//printf("%d\n", lot);
	if (con > 2) return;
	if (lot > h) {
		if (con == 2 || con == 0) {
			mould.push_back(value);
			dp[0][value] = 1;
		}
		return;
	}
	if(con==2 || con==0 )dfs(lot + 1, value << 1, 0);
	dfs(lot + 1, (value << 1) + 1, con + 1);
	return;
}
int main() {
	//初始状态的枚举
	while (1) {
		scanf_s("%d %d", &h, &w);
		if (h > w) swap(h, w);
		if (!h && !w) break;
		memset(dp, 0, sizeof(dp));
		mould.clear();
		dfs(1, 0, 0);
		int length = mould.size();
		for (int i = 1; i < length; i++) {
			for (int j = i + 1; j < length; j++) {
				if ((mould[i] & mould[j]) == 0) {
					mould.push_back(mould[i] + mould[j]);
					dp[0][mould[i] + mould[j]] = 1;
				}
			}
		}
		/*
		for (int i = 0; i < mould.size(); i++) {
			int res = mould[i];
			while (res) {
				printf("%d", res % 2);
				res /= 2;
			}
			printf("\n");
		}
		cout << "test" << endl;*/
		for (int i = 1; i < w; i++) {
			for (int j = 0; j < (1 << h); j++) {
				for (int k = 0; k < mould.size(); k++) {
					if ((j & mould[k]) == mould[k]) {
						dp[i][((~j) & ((1 << h) - 1)) + mould[k]] += dp[i - 1][j];
					}
				}
			}
		}
		/*
		for (int j = 0; j < w; j++) {
			for (int i = 0; i < ((1 << h) ); i++) {
				printf("%lld ", dp[j][i]);
			}
			printf("\n");
		}*/
		printf("%lld\n", dp[w - 1][(1 << h) - 1]);
	}
}

不知道递归的思路哪里产生了错误,一直WA。->再思考思考

解题思路一:将状态转化为填满的情况,0代表的是竖着铺的第一行,1代表的是其余的情况。

你可能感兴趣的:(算法刷题记录,算法)