我是靠谱客的博主 英俊春天,这篇文章主要介绍C语言笔记--基础“Hello world”一些特殊公式“计算”判断与循环位运算转移语句数组指针算法,现在分享给大家,希望可以做个参考。

“Hello world”

复制代码
1
2
3
4
5
6
7
#include<stdio.h> int main() { printf("Hello World!n"); return 0; }

一些新手常见错误

  • 没弄清赋值关系
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#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=%dn%d-%d=%dn%d*%d=%dn%d/%d=3n%d%%d=%dn",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=%dn",a,b,c); c=a-b; printf("%d-%d=%dn",a,b,c); c=a*b; printf("%d*%d=%dn",a,b,c); c=a/b; printf("%d/%d=%dn",a,b,c); c=a%b; printf("%d%%%d=%dn",a,b,c); return 0; }
  • 逻辑运算没弄清
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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进制

复制代码
1
2
3
4
5
6
7
if ( a=0xA | a >12 ) if ( 011&10==a ) printf (%d!n”,a); else printf (”Right!%dn”,a); else printf (”Wrong!%dn”,a);

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

simply printf()

字符

类比Hello World

计算 calculation

复制代码
1
2
3
4
5
6
7
#include <stdio.h> int main() { printf("23+43=%dn", 23+43);#%d代替后面的数值。 return 0; }

情景运用

  1. 超市购物
复制代码
1
2
3
4
5
6
7
8
9
10
11
#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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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不是有效的十六进制数字

一些问题解决

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h> main() { int a; char b; float c; printf("Please input an integer:"); scanf("%d", &a); printf("integer: %dn", a); printf("Please input a character:"); getchar(); /*将存于缓冲区中的回车字符读入,避免被后面的变量作为有效字符读入*/ scanf("%c", &b); printf("character: %cn", b); printf("Please input a float number:"); scanf("%f", &c); printf("float: %fn", c)

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

常见错误:
–scanf(“%d,%fn”,&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 )
赋值运算优先级高于逗号运算

复制代码
1
2
3
4
5
6
7
if ( a=0xA | a >12 ) if ( 011&10==a ) printf (%d!n”,a); else printf (”Right!%dn”,a); else printf (”Wrong!%dn”,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:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#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=%dn", 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=%dn”, n, j );
  break; /
控制退出循环 */
  }
}

continue

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

goto

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#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}

二维数组

基本的初始化方法

在这里插入图片描述在这里插入图片描述在这里插入图片描述

如何给开头一个元素赋值如何给开头一个元素赋值

输出

在这里插入图片描述
二维数组的几种输出方式
同时熟悉字符数组的赋值及输出以及一些特殊函数。
例题:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <string.h> main() {char words[5][15]={{''},{''},{''},{''},{''}},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("%sn",words[i]); printf("n"); }

指针

指针变量

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

指针运算符

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

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

指针与函数的关系

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

函数之间传递变量的地址

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
#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); }

指向函数的指针

  • 定义函数指针
    类型标识符(* 变量名)()
  • 给函数指针变量赋值
    函数指针变量=函数名
  • 通过指针变量调用函数
    (* 函数指针变量)(实际参数)
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
#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)。

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

基本模板:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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:
(后续对函数进行分析)

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#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%dn", &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("%dn", ans); } ———————————————— 版权声明:本文为CSDN博主「贝贝今天AC了吗」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_43787043/article/details/108506008

最后

以上就是英俊春天最近收集整理的关于C语言笔记--基础“Hello world”一些特殊公式“计算”判断与循环位运算转移语句数组指针算法的全部内容,更多相关C语言笔记--基础“Hello内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(103)

评论列表共有 0 条评论

立即
投稿
返回
顶部