[笔记][中国大学mooc][程序设计与算法(二) 算法基础][枚举][局部枚举法] POJ1222 熄灯问题

题目

在这里插入图片描述

分析

按照一般的穷举法,一共有30个开关,所以解空间有 2 30 2^{30} 230个可能,需要减少枚举数目:

如果存在某个局部,一旦这个局部的状态被确定,那么剩余其他部分的状态只能是确定的一种,或者不多的n种,那么就只需枚举这个局部的状态即可

对于本题目,第一行开关按下的状态可以决定剩余所有的状态,将解空间大小缩小为 2 5 2^{5} 25
在这里插入图片描述

代码

#include <stdio.h>
int solve(char puzzle[][6], char result[][6]){
	int cnt1, cnt2;
	for(cnt1 = 1; cnt1 < 5; cnt1++){
		for(cnt2 = 0; cnt2 < 6; cnt2++){
			if(puzzle[cnt1 - 1][cnt2] == 1){
				result[cnt1][cnt2] = 1;
				puzzle[cnt1 - 1][cnt2] = !puzzle[cnt1 - 1][cnt2];
				puzzle[cnt1][cnt2] = !puzzle[cnt1][cnt2];
				if(cnt1+1 < 5) puzzle[cnt1+1][cnt2] = !puzzle[cnt1+1][cnt2];
				if(cnt2-1 >= 0) puzzle[cnt1][cnt2-1] = !puzzle[cnt1][cnt2-1];
				if(cnt2+1 < 6) puzzle[cnt1][cnt2+1] = !puzzle[cnt1][cnt2+1];
			}
			else result[cnt1][cnt2] = 0;
		}
	}
	for(cnt2 = 0; cnt2 < 6; cnt2++) if(puzzle[4][cnt2] != 0) return 0;
	return 1;
}
int main(){
	int puzzleNumber;
	char puzzle[5][6];
	char puzzleTemp[5][6];
	char result[5][6];
	int cnt, cnt1, cnt2, cnt3, tmp;
	scanf("%d", &puzzleNumber);
	for(cnt = 0; cnt < puzzleNumber; cnt++){
		for(cnt1 = 0; cnt1 < 5; cnt1++)
			for(cnt2 = 0; cnt2 < 6; cnt2++)
				scanf("%d", &puzzle[cnt1][cnt2]);
		printf("PUZZLE #%d\n", cnt+1);
		//枚举,从00000到11111
		for(cnt3 = 0; cnt3 < 64; cnt3++){
			tmp = cnt3;
			//将枚举元分解为第一行的操作
			for(cnt2 = 0; cnt2 < 6; cnt2++){
				result[0][cnt2] = tmp % 2;
				tmp /= 2;
			}
			//模拟对象初始化
			for(cnt1 = 0; cnt1 < 5; cnt1++)
				for(cnt2 = 0; cnt2 < 6; cnt2++)
					puzzleTemp[cnt1][cnt2] = puzzle[cnt1][cnt2];
			//执行第一行操作
			for(cnt2 = 0; cnt2 < 6; cnt2++){
				if(result[0][cnt2] == 1){
					puzzleTemp[0][cnt2] = !puzzleTemp[0][cnt2];
					puzzleTemp[1][cnt2] = !puzzleTemp[1][cnt2];
					if(cnt2-1 >= 0) puzzleTemp[0][cnt2-1] = !puzzleTemp[0][cnt2-1];
					if(cnt2+1 < 6) puzzleTemp[0][cnt2+1] = !puzzleTemp[0][cnt2+1];
				}
			}
			//执行接下来几行的操作,观察是否可以熄灭所有灯
			if(solve(puzzleTemp, result))
				for(cnt1 = 0; cnt1 < 5; cnt1++)
					printf("%d %d %d %d %d %d\n", result[cnt1][0], result[cnt1][1], result[cnt1][2], result[cnt1][3], result[cnt1][4], result[cnt1][5]);
		}
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值