枚举——枚举进阶

思路:

这次枚举想法是基本不变的,但是却又一种新的做题思维,就是定状态,怎么说呢?

就是不用枚举所有状态,有些题目知道某部分的状态就知道下部分的状态,所以只需要枚举某局部的状态数量就行

下面直接来一道例题

题目链接:

POJ1222:EXTENDED LIGHTS OUT

题目:

Language:Default
EXTENDED LIGHTS OUT
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 12654 Accepted: 8030

Description

In an extended version of the game Lights Out, is a puzzle with 5 rows of 6 buttons each (the actual puzzle has 5 rows of 5 buttons each). Each button has a light. When a button is pressed, that button and each of its (up to four) neighbors above, below, right and left, has the state of its light reversed. (If on, the light is turned off; if off, the light is turned on.) Buttons in the corners change the state of 3 buttons; buttons on an edge change the state of 4 buttons and other buttons change the state of 5. For example, if the buttons marked X on the left below were to be pressed,the display would change to the image on the right. 

The aim of the game is, starting from any initial set of lights on in the display, to press buttons to get the display to a state where all lights are off. When adjacent buttons are pressed, the action of one button can undo the effect of another. For instance, in the display below, pressing buttons marked X in the left display results in the right display.Note that the buttons in row 2 column 3 and row 2 column 5 both change the state of the button in row 2 column 4,so that, in the end, its state is unchanged. 

Note: 
1. It does not matter what order the buttons are pressed. 
2. If a button is pressed a second time, it exactly cancels the effect of the first press, so no button ever need be pressed more than once. 
3. As illustrated in the second diagram, all the lights in the first row may be turned off, by pressing the corresponding buttons in the second row. By repeating this process in each row, all the lights in the first 
four rows may be turned out. Similarly, by pressing buttons in columns 2, 3 ?, all lights in the first 5 columns may be turned off. 
Write a program to solve the puzzle.

Input

The first line of the input is a positive integer n which is the number of puzzles that follow. Each puzzle will be five lines, each of which has six 0 or 1 separated by one or more spaces. A 0 indicates that the light is off, while a 1 indicates that the light is on initially.

Output

For each puzzle, the output consists of a line with the string: "PUZZLE #m", where m is the index of the puzzle in the input file. Following that line, is a puzzle-like display (in the same format as the input) . In this case, 1's indicate buttons that must be pressed to solve the puzzle, while 0 indicate buttons, which are not pressed. There should be exactly one space between each 0 or 1 in the output puzzle-like display.

Sample Input

2
0 1 1 0 1 0
1 0 0 1 1 1
0 0 1 0 0 1
1 0 0 1 0 1
0 1 1 1 0 0
0 0 1 0 1 0
1 0 1 0 1 1
0 0 1 0 1 1
1 0 1 1 0 0
0 1 0 1 0 0

Sample Output

PUZZLE #1
1 0 1 0 0 1
1 1 0 1 0 1
0 0 1 0 1 1
1 0 0 1 0 0
0 1 0 0 0 0
PUZZLE #2
1 0 0 1 1 1
1 1 0 0 0 0
0 0 0 1 0 0
1 1 0 1 0 1
1 0 1 1 0 1
题目大意:
是要你输入一个5行6列的灯,1代表灯开着,0代表灯关了。而每一次按按钮都会使该灯和上下左右的灯都改变(熄灭变为打开,打开变为熄灭)要你输出一种把全部灯都熄灭的方法(1为按下,0为没按下)
分析:

最简单的思想就是枚举全部开关灯的状态,然后逐个对比;但是有30个开关,全部状态就是要求2的30次方这么多个次数,是远远超出题目所给的范围的。

那么这道题我们要怎样做呢,我们可以发现,如果枚举第一行的开关状态,还有一些灯假如还没熄灭,那么第二行就必须按下第一行没熄灭的灯的下面一个按钮。

1、比如按完第一行后,第一行灯的状态为010010

2、还有两盏灯没熄灭,那么第二行必须按下010010,并且除了下面两列,其他都不能按下,不然第一行就会有灯不熄灭。按完了之后第一行就会变回000000(即全部熄灭),而第二行又会有灯没熄灭(那么只能由第三行来关闭它)

3、如此类推,第三行。。。那这样只需要枚举第一行的开关状态64次就行了

代码如下:

因为都是0和1,我们可以用二进制来代表该灯是否有木有亮,如果不熟悉二进制的话可以用二维数组保存

代码:

下面是二进制代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int beg[8]; //起始状态
int trans[8]; //中途改变状态
int swi[8]; //开关状态 

void setbit(int &num, int pos, int v){ //设置第num的数,使它的二进制pos位置变为v 
	if(v) num |= (1<<pos);
	else num &= ~(1<<pos);
}

void chanbit(int &num, int pos){ //改变数字num的第pos位数
	num ^= (1<<pos);
} 

int getbit(int num, int pos){  //得到num第pos位数
	return (num>>pos)&1;
}

int main(){
	int rnd = 0;
	int n;
	scanf("%d",&n);
	for(int t = 0; t < n; t++){
		memset(beg,0,sizeof(0));
		for(int i = 0; i < 5; i++){  //保存初始状态
			for(int j = 0; j < 6; j++){
				int tmp;
				scanf("%d",&tmp);
				setbit(beg[i],j,tmp);
			}
		}
		
		for(int i = 0; i < 64; i++){  //开始枚举第一行的状态
			memcpy(trans,beg,sizeof(beg));  //重置trans的状态
			swi[0] = i;
			for(int j = 0; j < 5; j++){  //这个循环就是已知第j行的开关状态,改变第j行的灯
				for(int q = 0; q < 6; q++){  
					if(getbit(swi[j],q)){
						if(q-1 >= 0) chanbit(trans[j],q-1);  
						chanbit(trans[j],q);
						if(q+1 < 6) chanbit(trans[j],q+1);
						chanbit(trans[j+1],q);
					}
				}
				swi[j+1] = trans[j];  //同解释
			}
			if(trans[4] == 0) break;  //如果最后一行是0,就代表灯都已经光了
		}
		//输出
		printf("PUZZLE #%d\n",++rnd);
		for(int i = 0; i < 5; i++){
			for(int j = 0; j < 6; j++){
				if(j) printf(" %d",getbit(swi[i],j));
				else printf("%d",getbit(swi[i],j));
			}
			printf("\n");
		}
	} 
	
	return 0;
} 
下面是数组代码:(摘自 点击打开链接
#include <stdio.h>  
  
int map[7][8], press[7][8];  
  
int Test(void)  
{  
    int i, j;  
  
    for (i=2; i<=5; i++)//更新press[][]的值  
    {  
        for (j=1; j<=6; j++)  
        {  
            press[i][j] = (map[i-1][j]+press[i-1][j]+press[i-1][j-1]+press[i-1][j+1]+press[i-2][j])%2;  
        }  
    }  
  
    for (j=1; j<=6; j++)//检验最后一行灯是否全部熄灭  
    {  
        if ((press[5][j-1]+press[5][j]+press[5][j+1]+press[4][j])%2 != map[5][j])  
           return 0;  
    }  
    return 1;  
}  
  
void Enum(void) //枚举第一行press的2^6中情况  
{  
    int i;  
  
    for (i=1; i<=6; i++)  
       press[1][i] = 0;  
  
    while (!Test()) //枚举的方法其实就是枚举6位二进制数的所有情况  
    {  
        press[1][1]++;  
        i = 1;  
        while (press[1][i] == 2)  
        {  
            press[1][i] = 0;  
            i++;  
            press[1][i]++;  
        }  
    }  
}  
  
int main()  
{  
    int T, t, i, j;  
  
    scanf("%d", &T);  
    for (t=1; t<=T; t++)  
    {  
        for (i=1; i<=5; i++)  
            for (j=1; j<=6; j++)  
                scanf("%d", &map[i][j]);  
        Enum();  
        printf("PUZZLE #%d/n", t);  
        for (i=1; i<=5; i++)  
        {  
            for (j=1; j<6; j++)  
                printf("%d ", press[i][j]);  
            printf("%d/n", press[i][6]);  
        }  
    }  
} 

(部分内容摘自程序设计与算法(二)算法基础

给出一道类似的例题 :8469:特殊密码锁

答案会在下次在此贴出


如果有眼前一亮的题目或者解答欢迎和楼主讨论 ε=ε=ε=┏(゜ロ゜;)┛ 楼主的QQ486291187.




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值