user-0 提问: 算法优化问题

回复:
user: user-1
content: 懂了，写法是很棒。

user: user-0
content: 引用 12 楼 user-1 的回复:那就不知道了，至少思路我认为没错。。。 他要求是拆除，但是思路确是保留

user: user-0
content: 引用 12 楼 user-1 的回复:那就不知道了，至少思路我认为没错。。。 做出来了  #include<stdio.h> void search(char str[500][500],int i,int j,int *k) {     str[i][j] = '!';     *k=*k-1;     if (k != 0)     {         if (str[i][j - 1] == '.'&&*k!=0)search(str, i, j - 1, k);          if (str[i + 1][j] == '.' &&* k != 0)search(str, i + 1, j, k);         if (str[i][j + 1] == '.' &&* k != 0)search(str, i, j + 1, k);         if (str[i - 1][j] == '.' &&* k != 0)search(str, i - 1, j, k);     } } int main() {     //输入     int n, m, k;     scanf("%d %d %d", &n, &m, &k);     char a[500][500] = { '\0' };     getchar();     for (int i = 1; i <= n; i++)     {         for (int j = 1; j <= m; j++) scanf("%c", &a[i][j]);         getchar();     }     //计算要搜索的节点数     int cnt = 0;     for (int i = 1; i <= n; i++)         for (int j = 1; j <= m; j++)             if (a[i][j] == '.') cnt++;     k = cnt - k;     //将要搜索的节点数和根节点传进函数     int o = 1;     for (int i = 1; i <= n; i++)     {         for (int j = 1; j <= m; j++)             if (a[i][j] == '.')             {                 search(a, i, j, &k);                  o = 0;                 break;             }         if (o == 0) break;     }     //输出     for (int i = 1; i <= n; i++)     {         for (int j = 1; j <= m; j++)         {             if (a[i][j] == '!')printf(".");             if (a[i][j] == '.')printf("X");             if (a[i][j] == '#')printf("#");         }         printf("\n");     }     return 0; }

user: user-1
content: 应该可以过的，你试试。 /* 	功能：迷宫砌墙 	作者：user-1 	日期：2019年11月7日10:36:56 */ #include <stdio.h> int n, m, k; char maze[501][501]; int get_flag(int row, int col) {// 返回周围的地形，二进制1表示墙，0表示空地 	int flag = 0; 	if (row - 1 < 0 || '.' != maze[row - 1][col]) {// 上 		flag |= 1;// 上用第0位表示 	} 	if (row + 1 >= n || '.' != maze[row + 1][col]) {// 下 		flag |= 1 << 1;// 下用第1位表示 	} 	if (col - 1 < 0 || '.' != maze[row][col - 1]) {// 左 		flag |= 1 << 2;// 左用第3位表示 	} 	if (col + 1 >= m || '.' != maze[row][col + 1]) {// 右 		flag |= 1 << 3;// 右用第4位表示 	} 	return flag; } int count_one(int num) {// 统计二进制的1的个数 	int count = 0; 	while (num > 0) { 		count += num & 1; 		num >>= 1; 	} 	return count; } void maze_two() { 	int row = 0, col = 0; 	int flag, one_num; 	int min_num = 1;// 1面空地 	while (k > 0) { 		if (col < 0) {// 下越界，不会发生这种情况 			col = 0;// 只是为了消除警告的写的 		} 		if (row < 0) {// 同上 			row = 0; 		} 		if (col >= m) {// 右越界 			col = 0; 			++row;// 下一层 		} 		if (row >= n) {// 遍历完迷宫 			++min_num;// 允许空地的数量加1 			row = col = 0;// 从头遍历 		} 		if ('.' != maze[row][col]) {// 不是空地 			++col;// 下一个 			continue; 		} 		flag = get_flag(row, col);// 四周的地形，二进制：1墙，0空地 		one_num = count_one(flag);// 四周的1的数量，即墙的数量 		if (4 == one_num) {// 四周全是墙 			maze[row][col] = 'X'; 			--k; 			++col;// 下一个 			continue; 		} 		if (3 == one_num) {// 3面墙 			maze[row][col] = 'X'; 			--k; 			flag ^= 0xF;// 取反 			if (1 == flag) {// 上方是空地 				--row;// 向上走 			} else if (2 == flag) {// 下方是空地 				++row;// 向下走 			} else if (4 == flag) {// 左边是空地 				--col;// 向左走 			} else if (8 == flag) {// 右边是空地 				++col;// 向右走 			} else { 				break;// 错误情况 			} 			continue; 		} 		// 当前位置四周有2面墙且整个地图无端点空地 		if (2 == one_num && 2 == min_num) { 			maze[row][col] = 'X';// 改为墙 			--k; 			if (flag >= 10) {// 上方有空地 				--row;// 向上走 			} else if (flag < 8) {// 右方有空地 				++col;// 向右走 			} else { 				++row;// 否则向下走 			} 			continue; 		} 		++col;// 当前位置不是最合适的点，继续遍历 	} } int main(void) { 	scanf_s("%d %d %d", &n, &m, &k); 	for (int i = 0; i < n; i++) { 		scanf_s("%s", maze[i], m + 1); 	} 	maze_two(); 	for (int i = 0; i < n; i++) { 		printf("%s\n", maze[i]); 	} 	return 0; } /* 以下示例全部测试通过 3 4 2 #..# ..#. #...  5 4 5 #... #.#. .#.. ...# .#.#  2 2 2 .. ..  2 3 4 ... ...  2 3 4 #.# ...  3 4 2 .... .##. .... */

user: user-1
content: 那就不知道了，至少思路我认为没错。。。

user: user-0
content: 引用 10 楼 user-1 的回复:应该可以过的，你试试。 /* 	功能：迷宫砌墙 	作者：user-1 	日期：2019年11月7日10:36:56 */ #include <stdio.h> int n, m, k; char maze[501][501]; int get_flag(int row, int col) {// 返回周围的地形，二进制1表示墙，0表示空地 	int flag = 0; 	if (row - 1 < 0 || '.' != maze[row - 1][col]) {// 上 		flag |= 1;// 上用第0位表示 	} 	if (row + 1 >= n || '.' != maze[row + 1][col]) {// 下 		flag |= 1 << 1;// 下用第1位表示 	} 	if (col - 1 < 0 || '.' != maze[row][col - 1]) {// 左 		flag |= 1 << 2;// 左用第3位表示 	} 	if (col + 1 >= m || '.' != maze[row][col + 1]) {// 右 		flag |= 1 << 3;// 右用第4位表示 	} 	return flag; } int count_one(int num) {// 统计二进制的1的个数 	int count = 0; 	while (num > 0) { 		count += num & 1; 		num >>= 1; 	} 	return count; } void maze_two() { 	int row = 0, col = 0; 	int flag, one_num; 	int min_num = 1;// 1面空地 	while (k > 0) { 		if (col < 0) {// 下越界，不会发生这种情况 			col = 0;// 只是为了消除警告的写的 		} 		if (row < 0) {// 同上 			row = 0; 		} 		if (col >= m) {// 右越界 			col = 0; 			++row;// 下一层 		} 		if (row >= n) {// 遍历完迷宫 			++min_num;// 允许空地的数量加1 			row = col = 0;// 从头遍历 		} 		if ('.' != maze[row][col]) {// 不是空地 			++col;// 下一个 			continue; 		} 		flag = get_flag(row, col);// 四周的地形，二进制：1墙，0空地 		one_num = count_one(flag);// 四周的1的数量，即墙的数量 		if (4 == one_num) {// 四周全是墙 			maze[row][col] = 'X'; 			--k; 			++col;// 下一个 			continue; 		} 		if (3 == one_num) {// 3面墙 			maze[row][col] = 'X'; 			--k; 			flag ^= 0xF;// 取反 			if (1 == flag) {// 上方是空地 				--row;// 向上走 			} else if (2 == flag) {// 下方是空地 				++row;// 向下走 			} else if (4 == flag) {// 左边是空地 				--col;// 向左走 			} else if (8 == flag) {// 右边是空地 				++col;// 向右走 			} else { 				break;// 错误情况 			} 			continue; 		} 		// 当前位置四周有2面墙且整个地图无端点空地 		if (2 == one_num && 2 == min_num) { 			maze[row][col] = 'X';// 改为墙 			--k; 			if (flag >= 10) {// 上方有空地 				--row;// 向上走 			} else if (flag < 8) {// 右方有空地 				++col;// 向右走 			} else { 				++row;// 否则向下走 			} 			continue; 		} 		++col;// 当前位置不是最合适的点，继续遍历 	} } int main(void) { 	scanf_s("%d %d %d", &n, &m, &k); 	for (int i = 0; i < n; i++) { 		scanf_s("%s", maze[i], m + 1); 	} 	maze_two(); 	for (int i = 0; i < n; i++) { 		printf("%s\n", maze[i]); 	} 	return 0; } /* 以下示例全部测试通过 3 4 2 #..# ..#. #...  5 4 5 #... #.#. .#.. ...# .#.#  2 2 2 .. ..  2 3 4 ... ...  2 3 4 #.# ...  3 4 2 .... .##. .... */  兄弟，喜提10分

user: user-1
content: 明显你的是暴力搜索，我的是沿着上一步搜好的继续搜，，，这差很多好吧。  虽然我没验证我的对不对。理论上是这样的。

user: user-1
content: 类似。。。。。

user: user-0
content: 引用 6 楼 user-1 的回复:[quote=引用 4 楼 张福泰zzz 的回复:] [quote=引用 2 楼 user-1 的回复:] 我的思路是：先遍历数组找端点（四周只有一个.其他都是#的点），将它改为X，找到了就在判断和他相邻的那个点，如果还是端点继续操作，如果不是就遍历剩余的数组，重复上面步骤，如果无端点，直接挑最少相邻（四周.最少）的点。  蔓延式操作。这样会超时的好像要用遍历树做[/quote]把代码贴出来我试试。[/quote] 这是我的第二种方法，跟你说的有点类似，排除特殊情况都超时了： #include<stdio.h> int main() { 	int n, m, k; 	scanf("%d %d %d", &n, &m, &k); 	char a[1000][500] = { '\0' }; 	getchar(); 	for (int i = 1; i <= n; i++) 	{ 		for (int j = 1; j <= m; j++) scanf("%c", &a[i][j]); 		getchar(); 	} 	for (int i = 1; i <= n; i++) 	{ 		for (int j = 1; j <= m; j++) 		{ 			int cnt = 0; 			if (a[i][j] == '.') 			{ 				if (a[i-1][j] == '.') cnt++; 				if (a[i+1][j] == '.') cnt++; 				if (a[i][j+1] == '.') cnt++; 				if (a[i][j-1] == '.') cnt++; 			} 			if (cnt == 1) 			{ 				a[i][j] = 'X'; 				k--; 			} 			if (k == 0)break; 			if ((k != 0) && (i == n) && (j == m)) 			{ 				i = 1; j = 1; 			} 		} 		if (k == 0)break; 	} 	for (int i = 1; i <= n; i++) 	{ 		for (int j = 1; j <= m; j++) printf("%c", a[i][j]); 		printf("\n"); 	} 	return 0; } 这是我的第一种方法，感觉挺对但是也是超时： #include<stdio.h> //判断修改后是否连通（找规律） int z(char a[1000][500]) { 	int cnt = 0; 	for(int i=1;i<900;i++) 		for (int j = 1; j < 450; j++) 		{ 			int cnt1 = 0; 			if (a[i][j] == '.') 			{ 				if (a[i+1][j] == '.') cnt1++; 				if (a[i][j+1] == '.') cnt1++; 				if (a[i-1][j] == '.') cnt1++; 				if (a[i][j-1] == '.') cnt1++; 			} 			if (cnt1 == 1) cnt++; 			if (cnt1 == 3) cnt--; 			if (cnt1 == 4)cnt -= 2; 		} 	if (cnt == 2) return 0; 	else return 1; } int main() { 	int n, m, k; 	scanf("%d %d %d", &n, &m, &k); 	char a[1000][500] = { '\0' }; 	getchar(); 	//输入数组          for (int i = 1; i <= n; i++) 	{ 		for (int j = 1; j <= m; j++) scanf("%c", &a[i][j]); 		getchar(); 	} 	//修改数组         for (int i = 1; i <= n; i++) 	{ 		for (int j = 1; j <= m; j++) 		{ 			if (a[i][j] == '.') 			{ 				a[i][j] = 'X'; 				if (z(a)) a[i][j] = '.'; 				else k--; 			} 			if (k == 0) break; 		} 		if (k == 0) break; 	} 	//输出数组         for (int i = 1; i <= n; i++) 	{ 		for (int j = 1; j <= m; j++) 			printf("%c", a[i][j]); 		printf("\n"); 	} 	return 0; }

user: user-1
content: 引用 4 楼 张福泰zzz 的回复:[quote=引用 2 楼 user-1 的回复:] 我的思路是：先遍历数组找端点（四周只有一个.其他都是#的点），将它改为X，找到了就在判断和他相邻的那个点，如果还是端点继续操作，如果不是就遍历剩余的数组，重复上面步骤，如果无端点，直接挑最少相邻（四周.最少）的点。  蔓延式操作。这样会超时的好像要用遍历树做[/quote]把代码贴出来我试试。

user: user-1
content: 引用 4 楼 张福泰zzz 的回复:[quote=引用 2 楼 user-1 的回复:] 我的思路是：先遍历数组找端点（四周只有一个.其他都是#的点），将它改为X，找到了就在判断和他相邻的那个点，如果还是端点继续操作，如果不是就遍历剩余的数组，重复上面步骤，如果无端点，直接挑最少相邻（四周.最少）的点。 蔓延式操作。这样会超时的好像要用遍历树做[/quote]遍历树是啥。

user: user-0
content: 引用 2 楼 user-1 的回复:我的思路是：先遍历数组找端点（四周只有一个.其他都是#的点），将它改为X，找到了就在判断和他相邻的那个点，如果还是端点继续操作，如果不是就遍历剩余的数组，重复上面步骤，如果无端点，直接挑最少相邻（四周.最少）的点。  蔓延式操作。这样会超时的好像要用遍历树做

user: user-0
content: 大一高程作业题

user: user-1
content: 我的思路是：先遍历数组找端点（四周只有一个.其他都是#的点），将它改为X，找到了就在判断和他相邻的那个点，如果还是端点继续操作，如果不是就遍历剩余的数组，重复上面步骤，如果无端点，直接挑最少相邻（四周.最少）的点。  蔓延式操作。

user: user-1
content: 哪儿的题啊，看着挺有意思的。有链接没