算法刷题记录(Day 4)

Flip Game(poj 1753)

原题链接
题目类型:枚举
刚开始看到这道题是很懵的,鉴于一个点的翻转会影响到旁边的其余的点,因此从哪一个点开始翻起、如何进行枚举、如何判定是否需要翻等等问题涌入了我的脑子里,进而在这里面思考了良久,也不能找到一个正解。
进一步地进行分析,我发现自己忘记了枚举的本质。试图寻找一个方案来进行判定这个点是否需要翻转在枚举类型的题目中是荒诞的,因此这个问题被pass掉。
从哪个点开始翻转直接决定了枚举的顺序问题,而从哪个点开始翻转这个问题从根本上就认定了点的翻转顺序会对最后的结果产生影响,而这是因为在直观上一次翻转会影响到棋子的颜色,但我们可以仅仅只是在最后查看棋子的颜色,将中间的过程转化为翻转的次数,并作用到原先的矩阵上,从而解决了这个问题。
从而,只需枚举16个点翻还是不翻2^16种情形即可。
需要注意的是,在枚举过程中可以适当进行剪枝。

#include
using namespace std;
int A[4][4], B[4][4], C[4][4];
int res = 17;

int main() {
	char c;
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 4; j++) {
			c = getchar();
			if (c == 'b') A[i][j] = 1;
			else A[i][j] = 0;
		}
		getchar();
	}
	
	for (int a = 0; a < 16; a++) {
		int c1 = 0;
		B[0][3] = a % 2, B[0][2] = (a >> 1) % 2, B[0][1] = (a >> 2) % 2, B[0][0] = (a >> 3) % 2;
		if (B[0][3]) c1++; if (B[0][2]) c1++; if (B[0][1]) c1++; if (B[0][0]) c1++;

		for (int b = 0; b < 16; b++) {
			int c2 = 0;
			B[1][3] = b % 2, B[1][2] = (b >> 1) % 2, B[1][1] = (b >> 2) % 2, B[1][0] = (b >> 3) % 2;
			if (B[1][3]) c2++; if (B[1][2]) c2++; if (B[1][1]) c2++; if (B[1][0]) c2++;

			for (int c = 0; c < 15; c++) {
				int c3 = 0;
				B[2][3] = c % 2, B[2][2] = (c >> 1) % 2, B[2][1] = (c >> 2) % 2, B[2][0] = (c >> 3) % 2;
				if (B[2][3]) c3++; if (B[2][2]) c3++; if (B[2][1]) c3++; if (B[2][0]) c3++;

				for (int d = 0; d < 15; d++) {
					int c4 = 0;
					B[3][3] = d % 2, B[3][2] = (d >> 1) % 2, B[3][1] = (d >> 2) % 2, B[3][0] = (d >> 3) % 2;
					if (B[3][3]) c4++; if (B[3][2]) c4++; if (B[3][1]) c4++; if (B[3][0]) c4++;
					//cout << c1+c2+c3+c4 << endl;
					/*if (c1 + c2 + c3 + c4 <= 4) {
						printf("hi");
					}*/
					//Ca matrix C
					if (c1 + c2 + c3 + c4 >= res) continue;//prune
					int index0 = 0, index1 = 0;
					memcpy(C, A, sizeof(A));
					for (int i = 0; i < 4; i++) {
						for (int j = 0; j < 4; j++) {
							if (B[i][j]) {
								C[i][j] ++;
								if (i - 1 >= 0) C[i - 1][j]++;
								if (j - 1 >= 0) C[i][j - 1]++;
								if (i + 1 < 4) C[i + 1][j]++;
								if (j + 1 < 4) C[i][j + 1]++;
							}
						}
					}
					//verify matrix C
					for (int i = 0; i < 4; i++) {
						for (int j = 0; j < 4; j++) {
							if (C[i][j] %2 == 0 && !index0) index0 = 1; //when 0 first appear 
							if (C[i][j] %2 == 1 && !index1) index1 = 1; //when 1 first appear
							if (index0 && index1) goto over;
						}
					}
					over:
					if (index1 && index0) continue; //both 0 and 1 appear
					else {
						if (c1 + c2 + c3 + c4 < res) res = c1 + c2 + c3 + c4;
					}
				}
			}
		}
	}
	if (res == 0) printf("0\n");
	else if (res == 17) printf("Impossible\n");
	else printf("%d\n", res);
} 

Changing Digits(poj 3373)

原题链接
题目类型:规定了搜索方向的dfs
关于整除

a/b 则a为被除数,b为除数,若a/b的余数为0,则b整除a 或者a 能被b整除

参考的题解

(原谅我不会写,以下是看了题解之后的一些总结)

首先看到该题,第一个映入脑子的事情是大精度的数据应该如何存储以及如何进行运算的问题。
高精度数据的处理问题
高精度问题的解决思路回归到最原始的关于加减乘除的手工作业上,依据处理规则来写出程序。加法和减法是每位运算,再处理进位和借位的问题,而乘法则转化为加法,除法转化为减法,这与计算机组成原理课上所学习的内容是相一致的。

解决了这个问题,但是会发现若在每次运算中都使用如上所述的方法进行计算可能会过于繁琐,而在上面所指示的题解中,利用了同余的性质,给出了一个同余的表格,鉴于k的大小是有限的,因此该表格含有n的位数*k个元素。

我们都知道DFS是一种穷举暴力的方式,当时觉得这个方式不可行的原因在于所需要穷举的个数太多,当有多个解满足条件时应该如何记录以方便后续的比较和结果的输出。但是我却忽略了穷举方向对于问题求解速率的影响。当我们规定好穷举的方向时,那么第一个解即为正确的解。

接下来就是关于DFS的方向问题了,参考的链接中已经有了较为详尽的阐述,我就不再赘述了。

总结:

星期五了欸。

你可能感兴趣的:(算法刷题记录,算法,leetcode,职场和发展)