POJ 1222 熄灯问题

考察知识点:遍历搜索空间,枚举

解题思路:

用数组元素
(1)  puzzle[i][j]表示位置(i, j)上灯的初始状态:1 表示灯是被点亮的;0 表示灯是熄灭的。用数组
元素press[i][j]表示为了让全部的灯都熄灭,是否要按下位置(i, j)上的按钮:1 表示要按下;
0 表示不用按下。由于第0 行、第0 列和第7 列不属于按钮矩阵的范围,没有按钮,可以假
设这些位置上的灯总是熄灭的、按钮也不用按下。

(2)  根据熄灯规则,如果矩阵press 是寻找的答案,那么按照press 的第一行对矩阵中的按钮
操作之后,此时在矩阵的第一行上:
 *如果位置(1, j)上的灯是点亮的,则要按下位置(2, j)上按钮,即press[2][j]一定取1;
 *如果位置(1, j)上的灯是熄灭的,则不能按位置(2, j)上按钮,即press[2][j]一定取0。
这样依据press 的第一、二行操作矩阵中的按钮,才能保证第一行的灯全部熄灭。而对矩阵
中第三、四、五行的按钮无论进行什么样的操作,都不影响第一行各灯的状态。依此类推

(3) 函数guess(),做两件事件。(1)根据press 第一行和puzzle
数组,按照熄灯规则计算出press 其他行的值,使得矩阵第1~4 行的所有灯都熄灭。(2)判断
所计算的press 数组能否熄灭矩阵第5 行的所有灯。如果能够就返回“true”,表示找到了答
案;否则返回“false”,表示没有找到答案。

(4)函数enumate(),对press 第一行的元素press[1][1]~ press
[1][6]的各种取值情况进行枚举。在每种取值情况下,分别调用guess(),看看是否找到了答
案。如果找到了答案,就返回主函数,否则继续下一种取值情况的判断


#include <stdio.h>

int puzzle[6][8];
int press[6][8];

bool guess()  //guess函数由第一行和PUZZLE数组计算其他行的press数组
{
    int c,r; //行和列
    for(r=1; r<5; r++)  
        for(c=1; c<7; c++)
            press[r+1][c]=(puzzle[r][c]+press[r][c]+press[r-1][c]+press[r][c-1]+press[r][c+1])%2;

    for(c=1; c<7; c++) //guess函数还可以用计算得到的数组判断是否能关闭第五行
        if((press[5][c-1]+press[5][c]+press[5][c+1]+press[4][c])%2!=puzzle[5][c])
            return (false);

    return (true);

}
void enumate()  //对press[1][1]~~press[1][6]  一行各列进行枚举并调用guess看是否 那个,你懂得
{
    int c;
    for(c=1; c<7; c++)
        press[1][c]=0;

    while(guess()==false)
    {
        press[1][1]++;
        c = 1;
        while(press[1][c]>1)
        {
            press[1][c]=0;
            c++;
            press[1][c]++;
        }
    }
    return ;
}

int main()
{
    freopen("in.txt","r",stdin);
    int cases,i,r,c;
    scanf("%d",&cases);
    for(r=0; r<6; r++)
        puzzle[r][0]=0;
    for(c=1; c<7; c++)
        puzzle[0][c]=0;

    for(i=0; i<cases; i++)
    {
        for(r=1; r<6; r++)
            for(c=1; c<7; c++)
                scanf("%d",&puzzle[r][c]);

        enumate();
        printf("PUZZLE #%d\n",i+1);

        for(r=1; r<6; r++)
        {
            for(c=1; c<7; c++)
                printf("%d",press[r][c]);
            printf("\n");
        }
    }
    return 0;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值