枚举算法实例应用(二)

news2024/11/24 5:20:49

枚举算法实例应用(二)

Extended Lights Out

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.

img

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.

img

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

题设分析:

根据题设可分析出以下两种潜在的规定:

  1. 开关按下的先后顺序与结果的正确性无关,即先按哪个后按哪个不改变最后一个开关按下时灯的亮灭情况。
  2. 每一个按钮按下多次时,将抵消前面按下时所产生的结果,即某按钮按下两次,将恢复至初始状态,即未按下按钮状态。所以按钮只有按下和没有按下两种情况,不妨用0表示没有按下,1表示按下。

解题分析:

  • 枚举,即暴力破解。第一想法自然是枚举所有可能的开关状态,对每一个状态计算一下最后的灯的亮灭情况,若均熄灭则表示该状态为解。

  • 每个开关有且仅有两种状态,且开关矩阵为5×6的矩阵,共30个开关,所以一共有 2 30 2^{30} 230种可能的解,是一个相当大的数据量。所以应考虑剪枝,以期减少枚举的轮次。

  • 不难想到,枚举一个“局部”,当局部被确定时,剩下的部分也随之确定,不可能发生变化,所以我们只需枚举确定的局部可能的情况即可,以此来极大程度上减少枚举的轮次。

  • 而通过开关操作事第一行全部熄灭就是这样的一个局部。如:当按下若干开关使得第一行灯全部熄灭,开关会使第二行该开关下面的灯的亮灭情况翻转,所以,第二行的开关按动方案也随之确定,即将第二行仍然亮着的灯的开关按下,至此第一、二行全部熄灭一次类推,而当按下第三行的开关时,并不会影响第一行灯的亮灭。

  • 所以,若按此方式到第五行开关完成按动之后第五行灯为全部熄灭状态则表明该第一行的局部是可行的,即找到一个解。若第5行开关按动完成之后后仍有未熄灭的灯,则表明以该第一行为局部的解是不可行方案,因此抛弃之,进行下一个第一行状态的试探直至出现第一个可行的方案即为解。

  • 综上,只需以第一行的 2 6 2^6 26种方案为局部进行 2 6 2^6 26次枚举即可。


假若以int数组来存储灯源矩阵,当灯源矩阵规模足够大时,int数组占用空间大的劣势就体现出来了。

因此考虑数据类型的内存占用问题:

  • int类型占用4B(字节)的内存大小,共4*8=32位,有符号数可表示 − 2 31 ∼ 2 31 − 1 -2^{31}\sim2^{31}-1 2312311内的整数,显然对于Extended Lights Out问题来说,远远超过了问题有效数值范围,以至于空间利用率极低。

  • char类型占用1B(字节)的内存大小,共1*8=8位。有符号数可表示 − 2 7 ∼ 2 7 − 1 -2^{7}\sim2^{7}-1 27271

  • 由于开关的有效的状态仅有两种,不难想到将其与二进制数及其运算挂钩。一个char类型变量由8位二进制数表示,因为该题灯源矩阵为5×6的矩阵,每一行共有6列,因此一个char类型变量足以存储一行的灯状态,共需5个char类型即可存储整个灯源矩阵。此时空间利用率将达到6/8=75%。同时,若等原矩阵为8列时,可达100%,当灯源矩阵大于8时,仅需再增加一个char类型变量表示即可。

  • 相比于int类型存极大的增加了空间利用率。


解题步骤:

在考虑采用char类型存储灯源矩阵后,新的问题迎面而来——运算。

  • char类型存储虽然大大减少了空间浪费,但是对于读取、设置某一行某一列灯的亮灭状态;以及对于当开关按下时,灯的亮灭状态的翻转是一个新的难题。
  • 由于二进制数的特殊性,可以想到采用位运算将二进制数的某一位置1、置1、取反等操作。对于位运算的应用,应该充分理解二进制运算的本质,及逻辑运算规则,在此不再阐述。读者可自行查阅二进制逻辑运算相关知识自行补充。

下面具体介绍关于本题结合二进制数及其逻辑运算以减少空间复杂度的算法:

读取二进制数第index位二进制值

函数参数中str为第n行的char类型数据,因为char类型占用8bit(位),所以对于该题,第六位为有效数据,高两位补充为0,无异议,

假设传入str为00011001,有效数据为第六位(011001)。计算机规定从右到左为位数递增次序。即:

011001
第5位第4位第3位第2位第1位第0位
  • 若要取“00x000”中的x,则需通过00x000&001000=x,得到x,问题转化为如何获取001000,首先想到的是,将000000中第index位置为1,需要通过for循环index次到第index位,将其置为1。

  • 但是CPU中有移位器,可以通过通过硬件快速实现读取第i位,比for循环要快的多且不占用更多的内存。

  • 因此我们将00x000和001000同时右移3位,得到00000x、000001,通过与逻辑与运算00000x&000001=x得到x。

综上:该子问题的解将简化为读取00x000第3位的x时,将00x000右移3位,再与1做逻辑与运算得到目标值x。

举例:

  1. 若要取第1位的0,则应将str右移1位,变为001100,通过与“000001”做逻辑与运算,即可得到当前最低位“0”与1做与运算的结果,即0&1=0,取到结果为0。
  2. 若要取第3位的1,则应将str右移3位,变为000011,通过与“000001”做逻辑与运算,即可得到当前最低位“1”与1做与运算的结果,即1&1=1,取到结果为1。
  3. 若要取第5位的0,则应将str右移5位,变为000000,通过与“000001”做逻辑与运算,即可得到当前最低位“0”与1做与运算的结果,即0&1=0,取到结果为0。

代码:

int GetBitOfIndex(char str, int index) {     //获取字符str的第index个比特
    return (str >> index) & 1;
}

设置二进制数的第index位的值

因为需要修改二进制数串str的值,所以应读入二进制数串str的指针,设置为引用类型,否则只能在函数内修改,无法作用于调用函数处。参数index、value为修改第index位的数值为value。

  • 将index位设置为1时,基本思路是将00x000的第index位和1做逻辑或运算,因为任何数与1做或运算恒等于1。

    所以该子问题的解将简化为设置00x000第3位的x为1时,将001000与00x000做逻辑或运算。而001000可以通过将1左移3位获得。

    该步代码描述为:

    *str = *str | (1 << index);
    
  • 将index位设置为0时,基本思路是将00x000与110111做逻辑与运算,其他位均为1,做与运算时数值保持不变,第三位和0做与运算时恒为0。

    所以该子问题的解将简化为设置00x000第3位的x为0时,将00x000与110111做逻辑与运算。而110111可以通过将1左移3位得到001000,再取反,得到110111。

    该步代码描述为:

    *str = *str & (~(1 << index));
    

代码:

void SetBitOfIndex(char *str, int index, int value) { //设置字符str的第index位为val
    if (value) {
        //若要设置为1,则将str与00...100...00(第index位为1,其余位为0)做或运算。
        *str |= (1 << index);
    } else {
        //若要设置为0,则将str与11...011...11(第index位为0,其余位为1)做与运算再取反。
        *str &= ~(1 << index);
    }
}

取反二进制数的第index位

因为需要修改二进制数串str的值,所以应读入二进制数串str的指针,设置为引用类型,否则只能在函数内修改,无法作用于调用函数处。参数index将第index位的数值取反。

对于某位取反运算的基本思路是做异或运算,即将00x000的第3位x与1做异或运算;

因为0 ^ 1 = 1,1 ^ 1=0。即任何数与1做异或运算为将该数取反。

用代码可描述为:

*str = *str ^ (1 << index);

代码:

void NegationBitOfIndex(char *str, int index) {//翻转字符str的第index位
    //将字符str与00...100...00(第index位为1,其余位为0)做异或运算
    *str ^= (1 << index);
}

输出开关 / 灯源 矩阵

较为简单不再赘述。

void MatrixOutput(char Matrix[]) {//输出开关矩阵
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 6; j++) {
            printf("%d", GetBitOfIndex(Matrix[i], j));
            if (j < 5) {
                printf(" ");
            }
        }
        printf("\n");
    }
}

设计算法主函数

由于解题分析可知,应设置如下变量:

准备工作
  • 存储题目输入的源灯矩阵;

    char OriginLights[5]={0,};       //存储源灯矩阵,默认均为0
    
  • 存储枚举时,开关起作用之后变化中的灯矩阵的亮灭状态;

    char ChangingLights[5]={0,};     //存储枚举时变化的灯矩阵,默认均为0
    
  • 存储能使所有灯都熄灭的开关矩阵;

    char result[5]={0,};             //存储结果按钮矩阵,默认均为0
    
  • 读入源灯矩阵。

    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 6; j++) {
            int bit;
            scanf("%d", &bit);
            //设置源灯矩阵第i行第j列为bit
            SetBitOfIndex(&OriginLights[i], j, bit);
        }
    }
    

算法主体
  1. 有解题分析知,需要以第一行为局部进行枚举,因为第一行由6位二进制数组成,所以应有 2 6 = 64 2^6=64 26=64种排列方式。用0~63记录这64次枚举。


  2. 再每一轮次的局部状态枚举中,首先应将源灯状态矩阵Origin Lights由变化中的灯矩阵Changing Lights暂存起来进行运算,以保护下次枚举时源灯矩阵的正确性。可以通过string.h头文件下memcpy()函数完成。

    即:

    //将源灯矩阵的前sizeof(OriginLights)位,即前6位存入ChangingLights中进行后续运算
    memcpy(ChangingLights, OriginLights, sizeof(OriginLights));
    

  3. 在这64次以第一行局部状态开始的枚举中,开始依次处理第i行开关,由题设分析知:当第1行开关的按动次序确定之后,其余5行的开关次序也一并确定,所以,我们假设第i行开关已经确定为switchs。

    • 将第i行开关状态存入结果矩阵的第i行中,即存入result[i]。

    • 依次处理第i行的每一列:若第j列为1,表明灯是亮的,应按下(i,j)处按钮将其熄灭,但同时也会导致(i,j-1)、(i,j+1)两个位置的灯的状态翻转。故而应分情况讨论:

      1. 若j=0,即第一列时,影响本位、右位。
      2. 若0<j<5,即非两边届时,影响左位、本位、右位。
      3. 若j=5,则表示为最右侧一列,仅影响左位和本位。

      化简后可表述为:

      for (int j = 0; j < 6; j++) {
          if (GetBitOfIndex(switchs, j) == 1) {
              if (j > 0)
                  //翻转第i行,j-1列的灯的亮灭情况
                  NegationBitOfIndex(&ChangingLights[i], j - 1);
              //翻转第i行,j列的灯的亮灭情况
              NegationBitOfIndex(&ChangingLights[i], j);
              if (j < 5)
                  //翻转第i行,j+1列的灯的亮灭情况
                  NegationBitOfIndex(&ChangingLights[i], j + 1);
          }
      }
      
    • 若该行不为最后一行,则应处理对该行开关改动时所影响的下一行的灯的亮灭状态。

      只需将该下一行的灯的状态与switchs做一次异或运算即可翻转该列的灯的状态。

      比如:

      本行按动开关的状态为011001,即按下第1,2,5列开关

      下一行灯矩阵状态为100101,因为任何数与1做异或运算均可得到该数的相反数,所以通过下一行灯状态与本行开关状态做异或运算将本行开关状态影响的下一行灯的状态进行翻转。

      如011001^100101=111100,将100101,1、2、5位翻转为111100

      即:

      if (i < 4) {//若当前不是最后一行则翻转下一行开关所影响的灯的亮灭。
          //翻转i+1行switchs为1的bit位的灯亮灭情况
          ChangingLights[i + 1] ^= switchs;
      }
      
    • 此时第i行开关影响灯的亮灭状态的处理已经完成,那么第i+1行开关状态此时也就随之确定,即按动开关后应熄灭第i行的所有灯,所以switchs应修改为第i行的灯的状态。

      即:

      //当第i行确定之后,第i+1行也随之确定,即第i+1行开关熄灭第i行还亮着的灯即可
      switchs = ChangingLights[i];
      
    • 至此,本轮次局部状态的枚举处理已经完成,若此时最后一行的灯均为熄灭状态,则表示该局部状态为一个解,输出此时的开关矩阵即可,同时退出循环。

      即:

      if (ChangingLights[4] == 0) {//所有灯均已熄灭,表明本局部状态下的开关矩阵为解
          //输出解,即开关矩阵
          MatrixOutput(result);
          break;
      }
      

  4. 算法已经结束,只需再依据题目输入输出规则进行简单修改即可提交,此步不在赘述。

代码整合:
int GetBitOfIndex(char str, int index) {     //获取字符str的第index个比特
    return (str >> index) & 1;
}

void SetBitOfIndex(char *str, int index, int value) { //设置字符str的第index位为val
    if (value) {
        //若要设置为1,则将str与00...100...00(第index位为1,其余位为0)做或运算。
        *str |= (1 << index);
    } else {
        //若要设置为0,则将str与11...011...11(第index位为0,其余位为1)做与运算。
        *str &= ~(1 << index);
    }
}

void NegationBitOfIndex(char *str, int index) {//翻转字符str的第index位
    //将字符str与00...100...00(第index位为1,其余位为0)做异或运算
    *str ^= (1 << index);
}

void MatrixOutput(char Matrix[]) {//输出开关矩阵
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 6; j++) {
            printf("%d", GetBitOfIndex(Matrix[i], j));
            if (j < 5) {
                printf(" ");
            }
        }
        printf("\n");
    }
}

void ExtentedLightsOut() {
    char OriginLights[5] = {0,};       //存储源灯矩阵,默认均为0
    char ChangingLights[5] = {0,};     //存储枚举时变化的灯矩阵,默认均为0
    char result[5] = {0,};             //存储结果按钮矩阵,默认均为0

    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 6; j++) {
            int bit;
            scanf("%d", &bit);
            //设置源灯矩阵第i行第j列为bit
            SetBitOfIndex(&OriginLights[i], j, bit);
        }
    }

    for (int n = 0; n < 64; n++) {
        int switchs = n;//当前行的开关状态
        //将源灯矩阵的前sizeof(OriginLights)位,即前6位存入ChangingLights中进行后续运算
        memcpy(ChangingLights, OriginLights, sizeof(OriginLights));
        for (int i = 0; i < 5; i++) {//处理第i行开关,此时第i行开关状态已经确定为switchs
            result[i] = switchs;//暂存如result[i]中。
            for (int j = 0; j < 6; j++) {
                if (GetBitOfIndex(switchs, j) == 1) {
                    if (j > 0)
                        //翻转第i行,j-1列的灯的亮灭情况
                        NegationBitOfIndex(&ChangingLights[i], j - 1);
                    //翻转第i行,j列的灯的亮灭情况
                    NegationBitOfIndex(&ChangingLights[i], j);
                    if (j < 5)
                        //翻转第i行,j+1列的灯的亮灭情况
                        NegationBitOfIndex(&ChangingLights[i], j + 1);
                }
            }
            if (i < 4) {//若当前不是最后一行则翻转下一行开关所影响的灯的亮灭。
                //翻转i+1行switchs为1的bit位的灯亮灭情况
                ChangingLights[i + 1] ^= switchs;
            }
            //当第i行确定之后,第i+1行也随之确定,即第i+1行开关熄灭第i行还亮着的灯即可
            switchs = ChangingLights[i];
        }
        if (ChangingLights[4] == 0) {//所有灯均已熄灭,表明本局部状态下的开关矩阵为解
            //输出解,即开关矩阵
            MatrixOutput(result);
            break;
        }
    }
}

b y ⋯ S s 1 T w o ⋯ 2023 / 01 / 10 by\cdots Ss1Two\cdots2023/01/10 bySs1Two2023/01/10

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/154696.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是云原生(非常详细)

云原生计算加速了应用与基础设施资源之间的解耦&#xff0c;通过定义开放标准&#xff0c;向下封装资源&#xff0c;将复杂性下沉到基础设施层&#xff1b;向上支撑应用&#xff0c;让开发者更关注业务价值。此外&#xff0c;云原生计算提供统一的技术栈&#xff0c;动态、混合…

LabVIEW创建Web服务

LabVIEW创建Web服务在LabVIEW项目中开发Web服务&#xff0c;组合并配置构成Web服务的VI和其他文件。按照下列步骤创建一个Web服务项目和两个HTTP方法VI。创建一个组织Web服务文件的LabVIEW项目。将项目保存为Tutorial.lvproj。右键单击我的电脑并选择新建Web服务。LabVIEW在该终…

C语言基本数据类型

一、float、double和 long double 1.1 声明浮点型变量 1.2浮点型常量 1.3 打印浮点值 二、复数和虚数类型 三、其他类型 一、float、double和 long double 对于金融和数学的程序经常使用浮点数&#xff0c;而C语言中的浮点类型有float、double和 long double类型。常见的…

CentOS Stream 9下RabbitMQ安装教程(最新RabbitMQ安装教程)

CentOS Stream 9 RabbitMQ安装教程前言Erlang下载安装RabbitMQ下载安装启动RabbitMQ配置RabbitMQManagement Plugin访问和权限日志文件和管理总结和收获如果博主的文章对您有所帮助&#xff0c;可以评论、点赞、收藏&#xff0c;支持一下博主!!!前言 操作系统&#xff1a;Cent…

RocketMQ消息短暂而又精彩的一生

核心概念 NameServer&#xff1a;可以理解为是一个注册中心&#xff0c;主要是用来保存topic路由信息&#xff0c;管理Broker。在NameServer的集群中&#xff0c;NameServer与NameServer之间是没有任何通信的。Broker&#xff1a;核心的一个角色&#xff0c;主要是用来保存消息…

刚录制德云社相声春晚,又带领徒弟排练京剧,郭德纲成功不是偶然

不知道大家有没有发现一种现象&#xff0c;很多人在底层的时候&#xff0c;都是削尖了脑袋往前钻&#xff0c;可是一旦有一天功成名就&#xff0c;就会刀兵入库马放南山。这种做法通俗地讲&#xff0c;就是功成名就激流勇退&#xff0c;比如马云、刘强东、黄征等互联网企业大佬…

【RabbitMQ】MQ的基本概念、RabbitMQ简介及安装

文章目录MQ的基本概念MQ概述MQ 的优势和劣势常见的MQ产品RabbitMQ简介RabbitMQ的安装1. 安装依赖环境2. 安装Erlang3. 安装RabbitMQ4. 开启管理界面及配置5. 启动6. 配置虚拟主机及用户用户角色Virtual Hosts配置创建Virtual Hosts设置Virtual Hosts权限MQ的基本概念 MQ概述 …

Python3,我把新年祝福写在“雨“中,你看,雨一直下,气氛还算融洽,在同个屋檐下....

新年愿望写在"雨"中1、引言2、代码实战2.1 模块介绍2.1.1 Pygame 介绍2.1.2 Pygame的display介绍2.1.3 Pygame的event介绍2.1.4 Pygame的font介绍2.2 代码示例3、总结1、引言 小屌丝&#xff1a;鱼哥&#xff0c;2023年了&#xff0c; 你有啥愿望啊&#xff1f; 小鱼…

同消费互联网时代的轰轰烈烈相比,产业互联网似乎低调了许多

毫无疑问的是&#xff0c;一场衍生于产业的深度变革正在上演。在这样一场深度变革之中&#xff0c;曾经看似无法改变的存在&#xff0c;有了进化的可能性&#xff1b;曾经让玩家们望而却步的领域&#xff0c;有了进军的可能性。如果对这样一场深度变革进行一次总结的话&#xf…

测试分类那么多,哪些是你最需要掌握的内容?

目录 一、按照测试对象分类 1.1、可靠性测试 1.2、容错性测试 1.3、安装卸载测试 1.4、内存泄漏测试 1.5、弱网测试 二、按照是否查看代码分类 2.1、黑盒测试&#xff08;系统测试&#xff09; 2.2、白盒测试&#xff08;单元测试&#xff09; 2.3、灰盒测试&#xff0…

[数据结构1-1] 线性表

P3156 【深基15.例1】询问学号 题目描述 有 n ( n≤210^6) 名同学陆陆续续进入教室。我们知道每名同学的学号&#xff08;在 1 到 10^9之间&#xff09;&#xff0c;按进教室的顺序给出。上课了&#xff0c;老师想知道第 i个进入教室的同学的学号是什么&#xff08;最先进入…

浅谈IT自动化运维体系

大家好&#xff0c;今天我们来简单介绍一下 IT自动化运维的体系。 随着IT运维体系的不断发展&#xff0c;IT自动化运维已经成为IT运维体系的重要组成部分&#xff0c;并将随着信息化的发展发挥着越来越重要的作用。面对复杂的业务和多样化的用户需求&#xff0c;IT架构体系需要…

防微杜渐,未雨绸缪,百度网盘(百度云盘)接口API自动化备份上传以及开源发布,基于Golang1.18

奉行长期主义的开发者都有一个共识&#xff1a;对于服务器来说&#xff0c;数据备份非常重要&#xff0c;因为服务器上的数据通常是无价的&#xff0c;如果丢失了这些数据&#xff0c;可能会导致严重的后果&#xff0c;伴随云时代的发展&#xff0c;备份技术也让千行百业看到了…

LINUX提权之信息收集篇

前言 准备开一个新坑&#xff0c;最近在学linux提权&#xff0c;于是打算用几篇文章来记录一下linux提权的重要知识点。首先第一篇文章介绍一下linux权限的基础信息以及如何进行信息收集。 LINUX权限简介 因为我们要学习权限提升&#xff0c;所以在学习提权之前我们先了解一…

ThinkPHP多语言文件包含RCE(QVD-2022-46174)

漏洞范围 v6.0.0<ThinkPHP<v6.0.13v5.0.0<ThinkPHP<5.0.12v5.1.0<ThinkPHP<5.1.8 需开启多语言选项&#xff0c;以thinkPHP6版本为例 在自定义中间件定义文件app/middleware.php中添加\think\middleware\LoadLangPack::class php需安装pearcmd拓展,并且开…

文档控件Aspose.words for.java 授权须知

支持的平台 Aspose.Words 可作为 .NET、Java、C 和 Python 的四种不同产品使用&#xff0c; .NET Framework.NET Standard 2.0Xamarin.AndroidXamarin.iOSXamarin.MacCOMMonoWindows Azure 系统要求 任何可以运行 Java Runtime Environment (JRE) 的操作系统都可以运行 Aspo…

02FPGA的巨大优势

在FPGA诞生的初期&#xff0c;计算机研究员是最先感受到FPGA的巨大优势的。 在此之前&#xff0c;要想实现一个新计算机体架构的设计想法&#xff0c;必须要开发一个ASIC作为原型&#xff0c;在面板上安装很多个体积庞大的IC。 但是&#xff0c;与这些需要投入巨大成本和精力…

I2C上拉电阻的选择-计算公式

I2C一般为开漏结构&#xff0c;需要在外部加上拉电阻&#xff0c;常见的阻值有1k、1.5k、2.2k、4.7k、5.1k、10k等。 但是应该如何根据开发要求选择合适的阻值呢&#xff1f; 假设SDA是低电平时&#xff0c;即MOS管导通。那么&#xff0c;就可以求出上拉电阻R的阻值。 上拉…

Lodop指定纸张类型不生效问题

根据官网指定纸张类型的样例 https://www.lodop.net/demolist/PrintSample5.html发现按以下代码各种打印机预览和打印效果均不同LODOPgetLodop();LODOP.PRINT_INIT("");LODOP.SET_PRINT_PAGESIZE(1,800,600,"");//设置纸张为80mm*60mmLODOP.ADD_PRINT_HTM(…

埋点成本治理实战(字节)

0、序言 随着业务的发展&#xff0c;业务上报的埋点数据会越来越多&#xff0c;杂乱的埋点数据不仅会消耗计算和存储成本&#xff0c;造成巨大的成本浪费&#xff0c;也无法有效的应用于业务&#xff0c;给业务带去数据价值&#xff0c;因此埋点数据的治理就很有必要。 一、治…