C语言笔记--基础

“Hello world”

#include<stdio.h>

int main()
{
	printf("Hello World!\n");
	return 0;
}

一些新手常见错误

  • 没弄清赋值关系

#include<stdio.h>
int main()
{
	int a,b,c;
	scanf("%d%d",&a,&b);
    c=a+b;
    c=a-b;
    c=a*b;
    c=a/b;
    c=a%b;
	printf("%d+%d=%d\n%d-%d=%d\n%d*%d=%d\n%d/%d=3\n%d%%d=%d\n",a,b,c,a,b,c,a,b,c,a,b,c,a,b,c);
	return 0;
}
 

#include <stdio.h>   
   int main()   
 {   
    int a,b;   
   int c;   
 scanf("%d%d",&a,&b);   
   c=a+b;   
 printf("%d+%d=%d\n",a,b,c);   
    c=a-b;   
 printf("%d-%d=%d\n",a,b,c);   
    c=a*b;   
 printf("%d*%d=%d\n",a,b,c);   
    c=a/b;   
 printf("%d/%d=%d\n",a,b,c);   
    c=a%b;   
 printf("%d%%%d=%d\n",a,b,c);   
   return 0;   
}
  • 逻辑运算没弄清
#include<stdio.h>
int main()
{
	int a,b,c;
	scanf("%d%d%d",&a,&b,&c);
	if(a>b+c||b>a+c||c>a+b)
	printf("non-triangle.\n");
	else
	    if(a==b&&b==c)
	    printf("equilateral triangle.\n");
	    else
	      if ((a==b&&a!=c)||(a==c&&a!=b)||(b==c&&b!=a) )
	      printf("isoceles triangle.\n");
	      else
	      printf("triangle.\n");
	return 0;
}
/* 很容易直接翻译数学关系 从而弄错逻辑运算 如何 a==b==c*/ 

-不熟悉位运算和非10进制

if ( a=0xA | a >12 )
if ( 011&10==a )    printf (%d!\n”,a);
else                printf (”Right!%d\n”,a);
else printf (”Wrong!%d\n”,a);

011&010 == 1001&1010=1000=0x08

simply printf()

字符

类比Hello World

计算 calculation

#include <stdio.h>

int main()
{
    printf("23+43=%d\n", 23+43);#%d代替后面的数值。 

    return 0;
}

情景运用

  1. 超市购物
#include <stdio.h>

int main()
{
    int price = 0;

    printf("请输入金额(元):");
    scanf("%d", &price);

    int change = 100 - price;

    printf("找您%d元。\n", change);

    return 0;
}
  • 输出整型变量x对应的十进制、八进制和十六进制形式

方法一:

直接使用控制字符串

%o 八进制

%X 十六进制
方法二:

函数 char *itoa(int value, char *string, int radix)
返回值类型char
参数value 待转换的数字
参数string 转换后存储到string中
参数radix 转换到几进制
定义在 stdlib.h


#include <stdio.h>
#include <stdlib.h>
#define MAX 100
 
int main()
{
    int userinput;
    printf("Please enter a integer.\n");
    scanf("%d",&userinput);
 
    char octal[MAX],hex[MAX];
    itoa(userinput,octal,8);
    itoa(userinput,hex,16);
 
    printf("Octal and Hex of the integer %d that you entered is %s and %s.\n",userinput,octal,hex);
 
    return 0;
}
————————————————
版权声明:本文为CSDN博主「Cytosine」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Cytosine/article/details/59189577

一些特殊公式

  1. 吉姆拉尔森公式
    优化后的公式 : W= (d+2m+3(m+1)/5+y+y/4-y/100+y/400+1)%7
    =(d-1+y+y/4-y/100+y/400+2(m+1)+3(m+1)/5)%7
    公式原理

“计算”

变量

%c 字符 %s 字符串 %d 小数 &d 整数

  • 变量自增自减运算
    i++ 先使用变量的值 再加一++i 先加一 再使用变量的值
    同上 i-- --i
  • 复合运算符

    在这里插入图片描述

  • List item

如何定义变量

int char double float

关于getchar

字符输入: ch=getchar()
字符输出: putchar(ch)
//结合循环可实现字符串输入输出

关于scanf函数

1.scanf(“%d”,&A)
%3d 从头开始取三位 小数点算一位
%.3d 小数点后三位
%3.2d 小数点前三位,后两位

利用getchar()进行特殊的读取

eg:读取未知长度的数字;
scanf(),getchar()灵活结合。

其中一些details

1.sqrt(x) 求平方根
2.整数相除结果只取整数部分,小数丢弃。
3.sanf()不可以指定数据格式%m.n 会造成语言系统不理解 如:%4.2f
4.余数的符号取决于被除数
5.求余对象必须是整型!
6.(int)x 强制取整
7.c语言没有专门的逻辑字符 一般用 0 1
8.c语言中单引号里放字符 双引号里放字符串
9.或运算如果前面已经为真 后面就不会算了
10 ​已知int i=1; 执行语句while (i++<4) ;后,变量i的值为 答案:(5)
理解i++。
10.左对齐
在打印数字宽度前面加一个“-”,假设数字宽度为2,如果要打印的位数小于2,则在后面补足空格,如果要打印的位数大于2,则打印所有的数字,不会截断。
右对齐
在%和d之间加上数字宽度
假设数字宽度为 2,如果要打印的位数小于 2,左边补足空格;如果要打印的位数大于 2,则打印所有的数字,不会截断。

  1. 计算机计算规则
    已知:char c=‘A’; int i = 1, j;。执行语句 j = !c&&i++; 后,i 和 j 的值是:
    答:1和0。
    解析:c为真 !c则为假 &&后就不会执行了

if(!k)不等价与 if(k!=!0) 因为!0为1 后者意思为k!=1 显然与前者不同
11. 进制的表示
一、八进制由 0~7 八个数字组成,使用时必须以0开头(注意是数字 0,不是字母 o),例如:

//合法的八进制数
int a = 015; //换算成十进制为 13

int b = -0101; //换算成十进制为 -65

int c = 0177777; //换算成十进制为 65535

//非法的八进制

int m = 256; //无前缀 0,相当于十进制

int n = 03A2; //A不是有效的八进制数字

二、十六进制由数字 0~9、字母 A~F 或 a~f(不区分大小写)组成,使用时必须以0x或0X(不区分大小写)开头,例如:

//合法的十六进制int a = 0X2A; //换算成十进制为 42

int b = -0XA0; //换算成十进制为 -160

int c = 0xffff; //换算成十进制为 65535

//非法的十六进制

int m = 5A; //没有前缀 0X,是一个无效数字

int n = 0X3H; //H不是有效的十六进制数字

一些问题解决

#include <stdio.h>
main()
{
 int a;
 char b;
 float c;
 printf("Please input an integer:");
 scanf("%d", &a);
 printf("integer: %d\n", a);
 printf("Please input a character:");
 getchar(); /*将存于缓冲区中的回车字符读入,避免被后面的变量作为有效字符读入*/
 scanf("%c", &b);
 printf("character: %c\n", b);
 printf("Please input a float number:");
 scanf("%f", &c);
 printf("float: %f\n", c)

上一行的回车符会造成被后面当成变量输入 所以需要getchar()

常见错误:
–scanf(“%d,%f\n”,&a,&b);
–scanf(“%d,%f”,a,b);
–scanf(“%7.2f”,&a);

scanf(“%d%c%d”,a,b,c)这种情况下输入时不能打空格。

  • 4.double
    double精度比float更高
    double a;
    scanf(“%f”,&a); //应用scanf(“%lf”,&a);
    执行上面语句时,发现double类型的输入不能使用%f进行输入,得用%lf才能正常得到a的值。
    而在输出double类型时却可以用%f,这是因为printf(“%f”,a);在执行时C自动将float型的参数转换成double型!!!!
    故double型的输入输出形式如下:
    double a;
    scanf(“%lf”,&a);
    printf(“%f”,a);

数据类型

在这里插入图片描述

  • 隐式转换

精度低的向精度高的转换

在这里插入图片描述

  • 强制转换

(数据类型)x

表达式

(条件)?语句一:语句二 ?仅高于赋值运算符
为真语句一赋值给x 否则语句二赋值给x

运算符优先级

&&与 ||或 !非

-逗号运算符,
a=(xxx,xxx,xxx);其值为最后一个表达式的值

  • &取地址符 取指定变量的地址
  • 取负运算符
    将正数变负数 级别高
  • ()通常用于改变运算次序
  • []下标运算符 通常用于数组

已知int i,a; 执行语句"i=(a=23,a5),a+6;"后,变量i的值是 。 ( 30 )
赋值运算优先级高于逗号运算

if ( a=0xA | a >12 )
if ( 011&10==a )    printf (%d!\n”,a);
else                printf (”Right!%d\n”,a);
else printf (”Wrong!%d\n”,a);

① a=014时
第一个数为0,说明这个数是八进制
if(a=0xA | a>12):按照“运算符优先级”,先算a>12吗?八进制14等于十进制12,所以a不大于12。结果为0
第二步:0xA | 0 :十六进制A,按位或 0,结果肯定还是十六进制A了,任何数按位或0的话,等于任何数。所以这个if为真
第三步:if(011&10 == a):这里还是要考虑运算符的优先级,的优先级比&的优先级高,所以10a吗? 第二步可以看到,a的值已经变成0xA了,十六进制A等于十进制10,所以10a为真。真就是1
第四步:011&1 为真吗? 八进制011等于二进制1001,十进制1等于二进制0001,所以1001&0001 按位与后为0001 结果为真,所以执行printf(“%d!\n”, a)
第五步:第二步已经把a改变了,所以a等于10,结果10!
②a=0x14时
0x为十六进制,十六进制14等于十进制20,等于二进制10100
解答:
1、还是优先级的问题,20大于12吗?yes,yes为真为1
2、十六进制A等于二进制1010
3、1010 | 0001 结果为1011等于十进制11,所以这个时候a=11
4、if(011&10
a)
5、注意优先级 10==11吗?假,为0
6、011&0 八进制11,转化为二进制为1001&0000结果0000 假
7、第6的时候为假,所以执行else,结果为Right!11
结束!!
注意问题:
1、==的优先级大于&
2、>的优先级大于| 大于=
3、c语言是按顺序执行的,a=0xA | 先运算0xA,因为0xA后面有一个 | ,所以先执行| ,执行0xA | a,但是a后面有一个>,>的优先级又比|高,所以先执行>, 执行a>12,12后面没什么东西了,所以就先执行a>12 了。
4、考点:1、按顺序执行 2、运算符优先级
a=1+2+34 等于什么呢?按照数学的话,一眼看出来先执行34,但这里是C语言
按顺序执行,先执行1+2,2后面是+号,优先级一样,所以先执行1+2=3
3+34 — 3+3 但是3后面,所以这里就先执行*了,这时3+12
所以结果等于15

交换变量

转换

在这里插入图片描述

判断与循环

while语句

while(表达式)

在这里插入图片描述

for循环

在这里插入图片描述

新思路:双变量设置循环条件

在这里插入图片描述

switch

注意每一个case 中的 break
-case后每个常量必须各不相同。
-每个case后可执行语句可大于1,不必加{ }。
Demo1:

     #include <stdio.h>
     main ( )
     {   int x=1, y=0, a=0, b=0;
         switch ( x )
          {  case 1: switch ( y )
                     {  case 0:  a++;  break;
                        case 1:  b++;  break;
                     }
             case 2: a++;  b++;
                     break;
           }
           printf ("a=%d,b=%d\n", a, b );
     }

输出:a=2 b=1 易错:a=1 b=0
case1 后面没有break。

位运算

& 与
| 或
^异或
~ 求反 b=~a
x>>n x<<n移位号

在这里插入图片描述

转移语句

break

break语句的功能
1.在 switch 语句中结束 case 子句,使控制转到switch语句之外。
2.在循环语句的循环体中使用,结束循环过程,使控制转移到整个循环语句之外的下一条语句处。
例C6_6101.C:求 555555 的约数中最大的三位数是多少?

main( )
{ int j; long n;
 printf(“Please input number:”);
 scanf(“%ld”, &n);
  /* 所求约数取值范围999~100,j从大到小 /
 for (j=999; j>=100; j–)
  if ( n%j==0 ) /
若能整除j,则j是约数 /
  { printf(”3 digits in %ld=%d\n”, n, j );
  break; /
控制退出循环 */
  }
}

continue

continue语句的功能
continue语句仅能在循环语句中使用.
它的作用不是结束循环,而是开始一次新的循环。
对于for语句,将控制转到执行表达式3和条件测试部分;
对于while和do-while语句,将控制转到条件测试部分;
从逻辑上讲,适当改变程序的结构就可以不需要使用continue语句。

goto

goto语句的功能
1、将控制转移到标号所指定的语句处继续执行。
2、标号的唯一功能就是作为goto语句的目标。标号的作用域是它所在的整个函数。
goto语句的使用说明
在C语言中,goto 语句并不是必不可少的,使用 goto 语句的地方都可以用C的其它控制流程语句改写。

#include <stdio.h>
main( )
{ int a, b, c, d, i;
  for (a=1; a<=5; ++a)        /* 在a的范围内穷举 */
     for (d=1; d<=3; ++d)     /* 在d的范围内穷举 */
     {  b=a+(a+d)+(a+2*d)+(a+3*d); /* 前四项的和 */
 	      c=a*(a+d)*(a+2*d)*(a+3*d); /* 前四项的积 */
	      if ( b==26 && c==880 )    /* 若满足条件 */
	         goto  out;            /* 退出二重循环 */
	   }
  out:                        /* 语句标号 */
    for (i=0; i<=20; ++i)     /* 输出运行结果 */
       printf("%d,", a+i*d);
}

return(难理解)

retunrn 语句格式
格式一:return;
格式二:return (表达式);
return 语句的功能
1.return语句使程序从被调用函数中返回到调用函数的调用处继续运行。
2.如果return后跟一表达式,则该表达式的值会从被调用函数中带回到调用它的函数,称为返回值。

数组

数组:一组具有相同数据类型的数据的有序的集合。

  • 数组元素:构成数组的数据。数组中的每一个数组
    元素具有相同的名称,不同的下标,可以作为单个变
    量使用,所以也称为下标变量。
    • 数组的下标:是数组元素的位置的一个索引或指示。
    • 数组的维数:数组元素下标的个数。

一维数组

一维数组的定义方法为:
类型说明符 数组名[常量表达式];
一维数组通常和一重循环相配合,对数组
元素进行处理。
!!下标从0开始

赋值

例: int a[4]={1, 3, 5}
则a[0]=1,a[1]=3,a[2]=5,a[3]=0
int a[ ]={1, 3, 5}
相当于 int a[3]={1,3, 5}

二维数组

基本的初始化方法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

如何给开头一个元素赋值

如何给开头一个元素赋值

输出

在这里插入图片描述


二维数组的几种输出方式
同时熟悉字符数组的赋值及输出以及一些特殊函数。
例题:

#include <string.h>
main()
{char words[5][15]={{'\0'},{'\0'},{'\0'},{'\0'},{'\0'}},temp[15]={0};
 int i,j,k;
 scanf("%s",words[0]);
 for (i=1;i<5;i++)
    {    scanf("%s",temp);
        //strcpy(words[i],temp);
        j=i-1;
            while(strcmp(temp,words[j])<0)
            {
                strcpy(words[j+1],words[j]);
                j--;
            }    
            strcpy(words[j+1],temp);
    }
    for (i=0;i<5;i++)
        printf("%s\n",words[i]);
    printf("\n");
    }

指针

指针变量

说明方式: 数据类型 *变量名;
char *p;int *a;

指针运算符

& 取变量的地址 14
*取指针变量所指向的内容 14

p=&x;将指针指向x
*p=x无法取值

指针与函数的关系

features:
1.函数的返回值为指针。
2.通过参数在函数之间传递变量地址,既在函数之间传递指向变量的指针。
3.指针指向的对象使函数,称为函数指针。

函数之间传递变量的地址

在函数间传递变量地址时,变量的地址在调用函数时要作为实际参数,被调用函数时要作为实际参数,被调用函数使用指针变量作为形式参数接收传递的地址。
形式参数:int *p;
实际参数:&x;
注意:实参的数据类型要与作为形参的指针所指的对象的数据类型一致。

#include<stdio.h>
void main()
{
	int a,b,c;
	scanf("%d%d",&a,&b);
	c=plus(&a,&b);
	printf("A+B=%d',c);
}
plus(int *px,int *py)
{
 return (*px+*py);
}

指向函数的指针

  • 定义函数指针
    类型标识符(* 变量名)()
  • 给函数指针变量赋值
    函数指针变量=函数名
  • 通过指针变量调用函数
    (* 函数指针变量)(实际参数)
#include<stdio.h>
void main()
{
 int max(int,int);
 int (* pf)();
 int a,b,c;
 pf=max;
 scanf("   ");
 c=(* pf)(a,b);
 ..........
}

在函数的形参中使用指向函数的指针
形参是函数指针时,实参应为函数名,即函数在内存中的可执行代码的首地址(入口)

算法

贪心算法

贪心算法(greedy algorithm [8] ,又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解 [1] 。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择 [1] 。

思路:

贪心算法一般按如下步骤进行: [2]
①建立数学模型来描述问题 [2] 。
②把求解的问题分成若干个子问题 [2] 。
③对每个子问题求解,得到子问题的局部最优解 [2] 。
④把子问题的解局部最优解合成原来解问题的一个解 [2] 。
贪心算法是一种对某些求最优解问题的更简单、更迅速的设计技术。贪心算法的特点是一步一步地进行,常以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,省去了为找最优解要穷尽所有可能而必须耗费的大量时间。贪心算法采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择,就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解。虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪心算法不要回溯 [2] 。

使用条件:

利用贪心法求解的问题应具备如下2个特征 [4] 。
1、贪心选择性质
一个问题的整体最优解可通过一系列局部的最优解的选择达到,并且每次的选择可以依赖以前作出的选择,但不依赖于后面要作出的选择。这就是贪心选择性质。对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解 [4] 。
2、最优子结构性质
当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用贪心法求解的关键所在。在实际应用中,至于什么问题具有什么样的贪心选择性质是不确定的,需要具体问题具体分析 [4] 。

解题策略:

贪心算法不从整体最优上加以考虑,所做出的仅是在某种意义上的局部最优选择。使用贪心策略要注意局部最优与全局最优的关系,选择当前的局部最优并不一定能推导出问题的全局最优。贪心策略解题需要解决以下两个问题: [5]
1、该问题是否适合使用贪心策略求解,也就是该问题是否具有贪心选择性质 [5] ;
2、制定贪心策略,以达到问题的最优解或较优解 [5] 。
要确定一个问题是否适合用贪心算法求解,必须证明每一步所作的贪心选择最终导致问题的整体最优解。证明的大致过程为:首先考察问题的一个整体最优解,并证明可修改这个最优解,使其以贪心选择开始,做了贪心选择后,原问题简化为规模更小的类似子问题。然后用数学归纳法证明通过每一步做贪心选择,最终可得到问题的整体最优解 [5] 。

存在问题:

贪心算法也存在如下问题: [6]
1、不能保证解是最佳的。因为贪心算法总是从局部出发,并没从整体考虑 [6] ;
2、贪心算法一般用来解决求最大或最小解 [6] ;
3、贪心算法只能确定某些问题的可行性范围 [6] 。

参考:摘桃子(小学期)

高斯消元法

深度优先搜索法

基本概念
深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。

算法思想
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

在这里插入图片描述

基本模板:


int check(参数)
{
    if(满足条件)
        return 1;
    return 0;
}
 
void dfs(int step)
{
        判断边界
        {
            相应操作
        }
        尝试每一种可能
        {
               满足check条件
               标记
               继续下一步dfs(step+1)
               恢复初始状态(回溯的时候要用到)
        }
} 

问题示例

  1. 解谜游戏
  2. Description
    小张是一个密室逃脱爱好者,在密室逃脱的游戏中,你需要解开一系列谜题最终拿到出门的密码。现在小张需要打开一个藏有线索的箱子,但箱子上有下图所示的密码锁。

在这里插入图片描述

每个点是一个按钮,每个按钮里面有一个小灯。如上图,红色代表灯亮,白色代表灯灭。每当按下按钮,此按钮的灯以及其上下左右四个方向按钮的灯状态会改变(如果原来灯亮则灯灭,如果原来灯灭则灯亮)。如果小张通过按按钮将灯全部熄灭则能可以打开箱子。

对于这个密码锁,我们可以先按下左上角的按钮,密码锁状态变为下图。

在这里插入图片描述


再按下右下角的按钮,密码锁状态变为下图。

在这里插入图片描述


最后按下中间的按钮,灯全部熄灭。

在这里插入图片描述


现在小张给你一些密码锁的状态,请你告诉他最少按几次按钮能够把灯全部熄灭。

Input
第一行两个整数 n,m(1 \leq n,m \leq 16 ) 。

接下来 n 行,每行一个长度为 m 的01字符串,0表示灯初始状态灭,1表示灯初始状态亮。

Output
一行一个整数,表示最少按几次按钮可以把灯全部熄灭。

Notes
第一个样例见题目描述,第二个样例按左上和右下两个按钮。

测试用例保证一定有解。
测试输入 期待的输出 时间限制 内存限制 额外进程
测试用例 1 以文本方式显示
3 3↵
100↵
010↵
001↵
以文本方式显示
3↵

测试用例 2 以文本方式显示
2 3↵
111↵
111↵
以文本方式显示
2↵ANSWER:
(后续对函数进行分析)

#include <cstdio>
 
#define MAX_LEN 17
 
int n, m, a[MAX_LEN][MAX_LEN];
int cur[MAX_LEN][MAX_LEN];  //存储处理完第一排后的状态
int ans = 256;   //存储答案:最小步骤。初始为最大值256步
 
/* 将p位置上的整数做一个反(异或)操作:
 * 1变成0, 0变成1 */
void change(int *p) {
    if (*p == 1)
        *p = 0;
    else
        *p = 1;
}
 
/* 设定将a[i][j]处按下所产生的反应
 * 注意:a数组根据传递的地址而定 */
void push(int a[][MAX_LEN], int i, int j) {
    change(&a[i][j]);
    if (i - 1 >= 0)
        change(&a[i - 1][j]);
    if (j - 1 >= 0)
        change(&a[i][j - 1]);
    if (i + 1 < n)
        change(&a[i + 1][j]);
    if (j + 1 < m)
        change(&a[i][j + 1]);
}
 
/* 当第一排的灯被弄完后,把灯的状态复制到cur数组中
 * 便于后面的计数与操作,不会影响到原数组a */
void getCur() {
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            cur[i][j] = a[i][j];
}
 
/* 当第一排的灯被弄完后
 * 逐排操作,计算是否能够全部灭完
 * 如果不可以:返回-1;否则:返回操作次数 */
int calc() {
    getCur();
    int step = 0;
    for (int i = 0; i < n - 1; i++)
        for (int j = 0; j < m; j++) {
            if (cur[i][j] == 1) {
                step++;
                push(cur, i + 1, j);
            }
        }
 
    for (int i = 0; i < m; i++)
        if (cur[n - 1][i] == 1)
            return -1;
    return step;
}
 
/* 深度优先搜索,枚举第一排按键的所有按法
 * step: 当前讨论第1排第step + 1个按键
 * count: step之前按键一共被操作了的次数和 */
void dfs(int step, int count) {
    // 深度优先搜索的终点:讨论完第一排最后一个按键了
    // 已经按照一种方式将第一排操作完成
    if (step == m) {
        int t = calc();  //计算该基础上熄灭所有的灯需要的步数
        if (t == -1)  //无解
            return;
        if (t + count < ans)  //有解,更新最小值
            ans = t + count;
        return;
    }
 
    push(a, 0, step);  //按下第一排第step-1个按键
    dfs(step + 1, count + 1);
 
    push(a, 0, step); //再次按下(相当于还原)第一排第step-1个按键
    dfs(step + 1, count);
}
 
int main() {
    scanf("%d%d\n", &n, &m);  //一定要加上\n,作用:吸去换行符
 
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            char c;
            c = getchar();
            a[i][j] = c - '0';  //将字符转化为整数考虑
        }
        getchar();  //吸去换行符
    }
 
    dfs(0, 0);
    printf("%d\n", ans);
}

————————————————
版权声明:本文为CSDN博主「贝贝今天AC了吗」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43787043/article/details/108506008

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340