uva 10318 - Security Panel

本文提供了一种解决复杂灯泡开关谜题的算法实现,通过递归深度优先搜索策略来寻找最少的操作次数以达到所有灯泡开启的状态。文中详细介绍了如何使用C++编程语言进行实现,并展示了完整的代码。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <algorithm>
#define maxn 5 + 10
#define ll long long
#define INF 1000000000
#define FOR(i, a, b) for(int i = a; i < b; ++i)

using namespace std;
bool change[3][3], light[maxn][maxn];
int n, m, minlen;
int ans[maxn*maxn], finalans[maxn*maxn];
void lit(int x, int y)
{
    FOR(i, -1, 2) FOR(j, -1, 2)
    {
        int dx = x + i;
        int dy = y + j;
        if(x < 0 || y < 0 || x >= n || y >= m) continue;
        if(change[i+1][j+1]) light[dx][dy] = !light[dx][dy];
    }
    return;
}

bool check(int x)
{
    if(x < 0 || x >= n) return true;
    FOR(i, 0, m) if(!light[x][i]) return false;
    return true;
}

bool dfs(int cur, int len_ans)
{
    int x = cur/m, y = cur - m*x;
    if(x >= 2 && !check(x-2))
        return false;
    if(x == n-1 || cur == n*m)
    {
        if(check(n-1) && check(n-2)) {minlen = len_ans; return true;}
        if(cur == n*m) return false;
    }
    if(dfs(cur+1, len_ans)) return true;
        lit(x, y);
    ans[len_ans] = cur + 1;
    if(dfs(cur+1, len_ans+1)) return true;
        lit(x, y);
    return false;
}

int main()
{
    int kase = 0;
    while(scanf("%d%d", &n, &m), n+m)
    {
        memset(change, false, sizeof(change));
        memset(light, false, sizeof(light));
        minlen = INF;
        char s[3];
        FOR(i, 0, 3){ scanf("%s", s); FOR(j, 0, 3) change[i][j] = s[j] == '*'? true:false;}
        //FOR(i, 0, 3) {FOR(j, 0, 3) printf(change[i][j] == true? "*":"."); printf("\n");}
        printf("Case #%d\n", ++kase);
        if(dfs(0, 0))
        {
            printf("%d", ans[0]);
            FOR(i, 1, minlen) printf(" %d", ans[i]);
            printf("\n");
        }
        else puts("Impossible.");

    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值