"Competição de algoritmos·300 perguntas rapidamente" Uma pergunta por dia: "Jogo de iluminação de lâmpadas"

" Competição de Algoritmos: 300 Perguntas Rápidas " será publicado em 2024 e é um caderno de exercícios auxiliar para "Competição de Algoritmos" .
Todas as perguntas são colocadas no OJ New Online Judge , criado por você mesmo .
Os códigos são fornecidos em três linguagens: C/C++, Java e Python. Os tópicos são principalmente de nível médio a baixo e são adequados para alunos iniciantes e avançados.


" Jogo de iluminação de lâmpadas ", link: http://oj.ecustacm.cn/problem.php?id=1134

Descrição da pergunta

[Descrição do problema] Existe uma matriz de lâmpada n*n, b significa que a luz está escura e w significa que a luz está acesa. Cada lâmpada possui um botão que a controla. Quando um botão é pressionado, o botão e as luzes ao seu redor (cima, baixo, esquerda e direita) mudam de estado (claro -> escuro, escuro -> claro). O número mínimo de botões a serem pressionados para ligar ou desligar todas as luzes.
[Formato de entrada] Insira vários conjuntos de dados. A primeira linha de cada conjunto de dados possui um número inteiro n (1≤n≤10), e as próximas n linhas possuem n caracteres em cada linha representando a matriz inicial da lâmpada.
[Formato de saída] Se todas as lâmpadas puderem ficar claras ou escuras, produza o número mínimo de botões pressionados. Se não puder ser alcançado, imprima "Impossível" (sem aspas).
【Amostra de entrada】

4
bwwb
bbwb
bwwb
bwww
4
bwbw
wwww
bbwb
bwwb

【Amostra de saída】

4
Impossible

responder

   O “Jogo Lamplight” é um problema clássico com muitas soluções.
  Se não há limite de “número mínimo de botões” e só é necessário para atingir a escuridão total ou a extinção total, como operar? Aqui apresentamos um método denominado "método exaustivo de primeira linha", que é simples e fácil de implementar. Suponha que o objetivo é deixar todas as luzes pretas (escuras). A operação é a seguinte:
  (1) Não pressione o botão da primeira linha, apenas encontre a posição da luz branca;
  (2) A segunda linha corresponde para a posição da luz branca na primeira linha. , são todos botões. Quando pressionados, as luzes na parte superior, inferior, esquerda e direita mudarão de cor, especialmente as luzes brancas na linha anterior ficarão pretas, garantindo que o a primeira linha fica preta; (3) Os botões em cada linha correspondem à linha anterior
  . A luz branca torna toda a linha anterior preta.
  Esta questão requer o "número mínimo de botões".Você pode tentar todos os botões para encontrar o menor. Para reduzir o número de tentativas, você pode combinar os métodos acima. Para esta questão, n≤10, a escala é muito pequena, então este método violento também é viável.
  Supondo que o objetivo é deixar tudo preto no final, comece na primeira linha e pressione os botões linha por linha.
  A primeira linha tem um total de 16 maneiras de pressionar o botão de 0000 a 1111. 0000 significa não pressionar nenhum botão, 0001 significa pressionar apenas o 1º botão, 0010 significa pressionar apenas o 2º botão, 0011 significa pressionar o 1º e 2º botões,..., etc.
  Após selecionar um método na primeira linha, continue pressionando na segunda linha. Como pressionar a segunda linha? Obviamente você deve ter certeza de que a primeira linha fique preta. Então a posição do botão na segunda linha deve ser igual à posição do branco na primeira linha, porque depois que o botão na segunda linha for pressionado, o branco nele ficará preto.
  Continue pressionando as seguintes linhas de acordo com as regras acima até o final.
  Aqui estão alguns exemplos. O "estado inicial" na imagem é o primeiro exemplo de lâmpada. Preto significa escuro e branco significa claro. As coordenadas do canto superior esquerdo são (0,0) e as coordenadas do canto inferior direito são (3,3).
Insira a descrição da imagem aqui
  (1) Configurações dos botões na primeira linha. Tome como exemplo pressionar 0011 na primeira linha, o que significa pressionar o 1º e o 2º botões. Após pressionar o primeiro botão (0,0), você obtém a imagem (1), e após pressionar o segundo botão (0,1), você obtém a imagem (2). Grave as coordenadas (0,0) e (0,1) dos dois botões.
  (2) Configurações dos botões na segunda linha. Neste momento, apenas a segunda luz da primeira linha é branca e precisa ser transformada em preta. Em seguida, o segundo botão deve ser pressionado na segunda linha para fazer com que a luz branca acima se transforme em luz negra. As coordenadas dos botões que precisam ser pressionados na segunda linha são (1,1).O resultado da Figura (3) é obtido.A primeira linha é completamente preta.
  (3) Configurações dos botões na terceira linha. Como a segunda linha é toda preta, não há necessidade de pressionar a terceira linha.
  (4) Configurações dos botões na quarta linha. A terceira luz da terceira linha é branca e precisa ser preta. Em seguida, a quarta linha deve pressionar o terceiro botão para fazer com que a luz branca acima se transforme em luz negra. Como resultado da Figura (4), a terceira linha é completamente preta. As coordenadas do botão que precisa ser pressionado na quarta linha são (3,2).
  Após o término dessas quatro linhas, a quarta linha também ficou completamente preta, indicando que esta foi uma operação bem-sucedida e um total de 4 botões foram pressionados.
  Existem 16 métodos de configuração de botões na primeira linha. Siga as etapas acima. Entre eles, aquele que pressiona menos botões é a resposta que resulta em todas as luzes pretas.
  O texto acima assume que eles são todos pretos no final. Você também pode assumir que eles são todos brancos no final e fazer isso de novo. Pegar o menor número de botões é a resposta a esta pergunta.
  Os leitores são solicitados a codificar de acordo com esta ideia. O código abaixo é para referência.
【Pontos-chave】 Pensamento.

Código C++

#include<bits/stdc++.h>
using namespace std;
char Map[11][11];
int n;
int GetBit(int x, int i){
    
                 //取出x的第i位
    return (x >> i) & 1;
}
void SetBit(int &x, int i, int v){
    
            //将x的第i位设置成v
    if(v)  x |= (1 << i);
    else   x &= ~(1 << i);
}
void FlipBit(int &x, int i){
    
             //将x的第i位取反
    x ^= (1 << i);
}
int solve(){
    
    
    int oriLights[11];    //灯的初态
    int Lights[11];       //按动按钮之后的灯的新状态
    int result[11];       //存需要按动的按钮
    int ans = n * n + 1;  //需要按动的按钮数不会大于n*n
    memset(oriLights, 0, sizeof(oriLights));
    for(int i = 0; i < n; i++)           //把灯用二进制的位来表示,第i行,第j列
        for(int j = 0; j < n; j++){
    
    
            if(Map[i][j] == 'b')  SetBit(oriLights[i], j, 0);   //0表示暗
            else                  SetBit(oriLights[i], j, 1);   //1表示亮
        }
    for(int k = 0; k < (1<<n); k++)  {
    
            //k是第0行的按钮,有0000~1111种按钮设置
        memcpy(Lights, oriLights, sizeof(oriLights)); 
        int switchs = k;                      //第0行的按钮,例如k=0011,就是按第1、2个按钮
        for(int i = 0; i < n; i++) {
    
              //逐一处理每行的灯
            result[i] = switchs;              //用result[i]记录第i行的按钮
            for(int j = 0; j < n; j++) {
    
          //逐一处理每一列的灯
                if(GetBit(switchs, j)) {
    
       
                    if(j > 0)    FlipBit(Lights[i], j-1);  //j前面的第j-1灯变色
                    FlipBit(Lights[i], j);                     //第j个灯变色
                    if(j < n-1)  FlipBit(Lights[i], j+1);  //j后面的第j+1灯变色
                }
            }
            if(i < n-1)   Lights[i+1] ^= switchs;      //修改下一行的灯
            switchs = Lights[i];            //第i+1行按钮位置和第i行灯的位置相同
        }
        if(Lights[n-1] == 0) {
    
                //最后一行也全变黑了,成功
            int tmp = 0;                    //tmp为开关矩阵中1的数目
            for(int i = 0; i < n; i++)      //(i,j)就是需要按动的按钮坐标
                for(int j = 0; j < n; j++)
                    if(result[i] & (1<<j))
                        tmp++;
            ans = min(ans, tmp);
        }
    }
    return ans;
}
int main(){
    
    
    while(scanf("%d", &n) != EOF)  {
    
    
        memset(Map, 0, sizeof(Map));
        for(int i = 0; i < n; i++)  scanf("%s", Map[i]);
        int ans = solve();                  //以全黑为目标做一次
        for(int i = 0; i < n; i++)          //反过来以全白为目标做一次
            for(int j = 0; j < n; j++)
                if(Map[i][j] == 'b')  Map[i][j] = 'w';
                else                  Map[i][j] = 'b';
        ans = min(ans, solve());
        if(ans > n * n)  puts("Impossible");
        else             printf("%d\n", ans);
    }
    return 0;
}

Código Java

import java.util.*;  
public class Main {
    
      
    static int GetBit(int x, int i) {
    
    
        return (x >> i) & 1;
    }  
    static int SetBit(int x, int i, int v) {
    
    
        if (v == 1)   x |= (1 << i);
        else             x &= ~(1 << i);
        return x;
    }  
    static int FlipBit(int x, int i) {
    
    
        x ^= (1 << i);
        return x;
    }  
    static int solve(int n, String[] Map) {
    
    
        int[] oriLights = new int[n];
        for (int i = 0; i < n; i++) 
            for (int j = 0; j < n; j++) {
    
    
                if (Map[i].charAt(j) == 'b')  oriLights[i] &= ~(1 << j);
                else        oriLights[i] |= (1 << j);
            }
        int ans = n * n + 1;
        for (int k = 0; k < (1 << n); k++) {
    
    
            int switchs = k;
            int[] Lights = oriLights.clone();
            int[] result = new int[n];
            for (int i = 0; i < n; i++) {
    
    
                result[i] = switchs;
                for (int j = 0; j < n; j++) {
    
    
                    if (GetBit(switchs, j) == 1) {
    
    
                        if (j > 0)   Lights[i] = FlipBit(Lights[i], j-1);
                        Lights[i] = FlipBit(Lights[i], j);
                        if (j < n-1) Lights[i] = FlipBit(Lights[i], j+1);
                    }
                }
                if (i < n-1)      Lights[i+1] ^= switchs;
                switchs = Lights[i];
            }
            if (Lights[n-1] == 0) {
    
    
                int tmp = 0;
                for (int i = 0; i < n; i++) 
                    for (int j = 0; j < n; j++) 
                        if ((result[i] & (1 << j)) != 0) 
                            tmp++;
                ans = Math.min(ans, tmp);
            }
        }
        if (ans > n * n)     return -1;
        else             return ans;

    }
  
    public static void main(String[] args) {
    
    
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
    
    
            int n = scanner.nextInt();
            if (n == 0)  break; 
            String[] Map = new String[n];
            for (int i = 0; i < n; i++)  Map[i] = scanner.next();
             int ans = solve(n, Map);
            // 循环遍历数组并替换字符
            for (int i = 0; i < n; i++) {
    
    
                Map[i] = Map[i].replace('b', 'x');  // 将'b'替换为临时字符'x'
                Map[i] = Map[i].replace('w', 'b');  // 将'w'替换为'b'
                Map[i] = Map[i].replace('x', 'w');  // 将临时字符'x'替换为'w'
            }
            ans = Math.min(ans, solve(n, Map));
            if (ans == -1)   System.out.println("Impossible");
            else             System.out.println(ans);
        }
        scanner.close();
    }
}

Código Python

  

 import sys
def GetBit(x, i):   return (x >> i) & 1
 
def SetBit(x, i, v):
    if v:     x |= (1 << i)
    else:     x &= ~(1 << i)
    return x
 
def FlipBit(x, i):
    x ^= (1 << i)
    return x
 
def solve(n, Map):
    oriLights = [0] * n
    for i in range(n):
        for j in range(n):
            if Map[i][j] == 'b':  oriLights[i]=SetBit(oriLights[i], j, 0) 
            else:                 oriLights[i]=SetBit(oriLights[i], j, 1) 
    ans = n * n + 1
    for k in range(1 << n):
        switchs = k
        Lights = oriLights[:]
        result = [0] * n
        for i in range(n):
            result[i] = switchs
            for j in range(n):
                if GetBit(switchs, j):
                    if j > 0:   Lights[i] = FlipBit(Lights[i], j-1)
                    Lights[i] = FlipBit(Lights[i], j)
                    if j < n-1: Lights[i] = FlipBit(Lights[i], j+1)
            if i < n-1:   Lights[i+1] ^= switchs
            switchs = Lights[i]
        if Lights[-1] == 0:
            tmp = 0
            for i in range(n):
                for j in range(n):
                    if result[i] & (1 << j):
                        tmp += 1
            ans = min(ans, tmp)
    return ans
 
for line in sys.stdin:
    n = int(line.strip())
    if n == 0:  break
    Map = []
    for i in range(n):   Map.append(input().strip())
    ans = solve(n, Map)
    F = {
    
    }
    F['b'] = 'w'
    F['w'] = 'b'
    for i in range(n):
        Map[i] = ''.join([F[x] for x in Map[i]])
         
    ans = min(ans,solve(n, Map))
    if ans > n * n:     print("Impossible")
    else:               print(ans)

Acho que você gosta

Origin blog.csdn.net/weixin_43914593/article/details/132859917
Recomendado
Clasificación