C++之循环结构/动态规划(dp)讲义

本文是关于C++中循环结构和动态规划的讲义,涵盖上一讲复习习题、循环结构的基本概念和应用,包括自增自减运算符,以及求和、积模型和计数器模型的实例。同时介绍了动态规划的初步概念,后续内容敬请期待。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文的原文链接

一、上一讲复习习题

(每题 1 1 1 分,共 4 4 4 分)

1.下面代码的错误有哪些?

if(n%2==0){
	cout<<"Is a even.";
	else{
		cout<<"Is a odd."
	}
}
  • n未定义,且没有初始值。
  • else语句写的位置错误,应在if语句的后面写。
  • 第四行cout<<"Is a odd."处没有分号。
  • else在C++中没有定义,压根不能用,而不是位置错。

2.这个判断闰年的核心代码,是对的还是错的?

//year表示当前年份
cin>>year;
if(n/4==0&&n%400!=0){
	cout<<"Is a leap.";
}
if(n%400==0){
	cout<<"Is a leap.";
}
else{
	cout<<"Is not a leap.";
}
  • 正确。
  • 错误。有_______处错误。

3.下面是洛谷 P5716的核心代码,请说出下面代码的问题。

//year表示年份,month表示月份,isleap表示是否为闰年。
cin>>year>>month;
if(year%4==0||year%400==0){
	isleap=true;
} 
else{
	isleap=false;
}
if(month=1||month=3||month=5||month=7||month=8||month=10||month=12){
	cout<<"31"<<endl;
}
else if(month==4&&month==6&&month==9&&month==11){
	cout<<"30"<<endl;
}
else if(month==2){
	if(isleap){
		cout<<"29"<<endl;
	}
	else{
		cout<<"28"<<endl;
	}
}
  • 答:______________________________________________________________________________________________________。

4.读程序选输出。阅读程序,选择它的正确输出。(禁止运行程序)

#include<iostream>
using namespace std;
int main(){
	int b=4,a=1,c=4;
	int root=b*b-4*a*c;
	if(root>0){
		cout<<"2"<<endl;
	}
	else if(root==0){
		cout<<1<<endl;
	}
	else{
		cout<<0<<endl;
	}
	return 0;
}
  • "1"
  • 没有输出
  • 0
  • 1
  • "2"

二、循环结构课堂讲义

引导、概念普及

概念1:程序设计结构基础三要素:顺序结构、分支结构、循环结构

概念2:程序设计基础掌握内容:顺序结构、分支结构、循环结构、一/多维数组、字符串、函数/函数递归的理解

一、for循环

我们要列举大于等于数字 1 1 1 ,小于数字 6 6 6 的数字,怎么办呢?相信同学们都已经想好怎么写了,核心代码如下:

cout<<1<<endl;
cout<<2<<endl;
cout<<3<<endl;
cout<<4<<endl;
cout<<5<<endl;

如果我们要列举 99 99 99 个数, 999 999 999 个数, 9999 9999 9999 个数, 99999 99999 99999 个甚至更多的数,用这种方法岂不太低效了?

别急,我们可以用for循环解决。列举 1 1 1 99 99 99 的数的核心代码如下:

for(int i=1;i<100;i=i+1){
	cout<<i<<endl;
}

这里每个部分是什么呢?

for关键字到}结束的地方称为for循环。它是一种循环结构

for后面()内三个部分由;分隔,分别表示:进入循环前执行的语句(循环初始化)循环继续执行一次的条件判断(循环条件)每一次循环执行后会执行的语句(循环后执行语句)

任务1:分别输出 1 1 1 100 , 1000 , 10000 , 100000 , 1000000 100,1000,10000,100000,1000000 100,1000,10000,100000,1000000 的连续数字,想想怎么做?提示:我们可以用for循环解决问题。( 3 3 3 分)

答案:标程链接

任务2: 100 100 100 以内的正偶数。提示:每次i不一定+1,或用if解决问题?( 3 3 3 分)

答案:标程链接

二、自增和自减

我们要学习特殊的运算符,快速修改变量的值。

在之前的课程中,我们经常见到digit=digit+1digit=digit-1这样的语句。不难发现,表达式中=右边的值会被先计算出来,赋给=左边的digit(右结合),其起到了让digit+1的效果。

我们可以将x=x+1简写x+=1,类似的还有-=,*=,/=,%=等。

当我们对变量的值进行操作,每次增加或减少的量为确定的 1 1 1 时,C++语言还专门提供了专门的 自增运算符(increment operator) ++自减运算符(decrement operator) --

如果我们写a++++a,它实际达到的效果与a=a+1a+=1都是完全一致的。而如果我们写a----a则与a=a-1a-=1在效果上等价。

cout<<(a++);
cout<<(++a);

假设现在a的取值为5,上面这两行代码中第一句会输出的值是5;而同样在a取值为5的情况下,使用第二句则会输出6。这是因为表达式a++先被使用,之后再将a的值增加1,而++a则是先将a的值增加1然后才被使用!

在运算的速度上,速度的快慢如下:

++a > a++ > a+=1 > a=a+1

--a > a-- > a-=1 > a=a-1

任务三:输出 1 1 1 n n n 之间的连续正整数,要求使用新学的特殊符号。( 3 3 3 分)

答案:标程链接

知识:循环 n n n 次有 2 2 2 种写法,代码如下:

示例 1 1 1

int n;
cin>>n;
for(int i=1;i<=n;i++/*++i*/){

}

示例 2 2 2

int n;
cin>>n;
for(int i=0;i<n;i++/*++i*/){

}

三、求和/积模型

1.求 1 1 1 n n n 的和。

解法一:运用公式求解

( 1 + n ) × n 2 \LARGE{\frac{(1+n)\times n}{2}} 2(1+n)×n

代码实现:

int n;
cin>>n;
cout<<(1+n)*n/2<<endl;  //公式

解法二:利用循环累加求解

我们定义一个变量 s u m sum sum ,初始化为 0 0 0 ,从 1 1 1 循环到 n n n ,每次累加到 s u m sum sum 中,即可得出正确结果。注意:输出的是 s u m sum sum ,不是 n n n

代码实现:

int sum=0,n;
cin>>n;
for(int i=1;i<=n;i++){
	sum+=i;         //循环求解的关键
}
cout<<sum<<endl;

思考:如果求 1 1 1 n n n 的乘积 ( n ! n! n!),怎么办呢?

解法:利用循环求乘积

我们定义一个变量 f r a c frac frac ,初始化为 1 1 1 ,从 1 1 1 循环到 n n n ,每次乘到 f r a c frac frac 中,即可得出正确结果。注意: f r a c frac frac 的值必须初始化为 1 1 1

代码实现:

unsigned long long frac=1; //unsigned是一个整数类型,比 long long 还大。
int n;
cin>>n;
for(int i=1;i<=n;i++){
	frac*=i;        //同上
}
cout<<frac<<endl;

四、计数器模型

输入 n n n ,请找出 1 1 1 n n n 之间是 7 7 7 的倍数的个数。

解法:利用条件判断解决

我们定义一个计数器 c n t cnt cnt 0 0 0 ,表示目前尚未由满足要求的数。从 1 1 1 循环到 n n n ,如果这个数满足条件,那么 c n t cnt cnt 1 1 1 ,否则跳过,最后输出 c n t cnt cnt

代码实现:

int n,cnt=0;
cin>>n;
for(int i=1;i<=n;i++){
	if(i%7==0){    //重要的条件判断部分,计数器模型的核心
		cnt++;
	}
}
cout<<cnt<<endl;

总结的计数器模型:

int n,cnt=0; //初始化很重要!
cin>>n;
for(int i=1;i<=n;i++){
	if(/*条件部分*/){
		cnt++;
	}
}
cout<<cnt<<endl;

任务4:计算 1 − n 1-n 1n 的和。( 1 1 1 分)

任务5:计算 n ! n! n! ( n n n 的阶乘),数据大,要用unsigned long long解题。( 1 1 1 分)

任务6:计算 m m m n n n 之间个位是 7 7 7 的倍数的个数,保证 7 ≤ m ≤ n 7\leq m\leq n 7mn 。( 10 10 10 分)

五、进阶的求和/积模型

输入 n n n n n n 个正整数,求所有正整数(不包含 n n n)的总和/乘积。

解法:运用循环累加求解

和之前的求和/积模型一样,我们同样定义一个变量 s u m sum sum ,并初始化为 0 0 0 ,循环 n n n 次,在循环内部定义一个临时变量 x x x ,在这里, x x x 只在此次循环中有效。输入 x x x ,并将其累加到 s u m sum sum 中,输出 s u m sum sum ,亦可得出正确结果。

代码实现:

int n,sum=0;
cin>>n;
for(int i=1;i<=n;i++){
	int x;   //临时变量
	cin>>x;
	sum+=x;	 //关键
}
cout<<sum<<endl;

n n n 个数的乘积怎么办呢?

解法:运用循环乘求解

同样,我们定义一个变量 s u m sum sum ,并初始化为 1 1 1 ,循环 n n n 次,在循环内部定义一个临时变量 x x x ,在这里, x x x 只在此次循环中有效。输入 x x x ,并将其乘到 s u m sum sum 中,输出 s u m sum sum ,亦可得出正确结果。注意: s u m sum sum 必须初始化为 1 1 1

代码实现:

int n,sum=1; //必须初始化为1!
cin>>n;
for(int i=1;i<=n;i++){
	int x;
	cin>>x;
	sum*=x;	 //关键
}
cout<<sum<<endl;

六、求最大/最小的数(打擂台算法)

大家看过电视节目吗?在节目中,怎么确定最强的人呢?①把第一个人作为擂主。②挑战者上台与擂主比赛。③如果挑战者胜,则其成为新的擂主,如果挑战者败,则原擂主还是擂主。重复②、③步骤,直到所有人比完。最终的擂主为最强的人。

在求最大/最小的数时,我们也可以把数比大小的过程比作打擂台。比如在1 8 9 4 3 10六个数中,我们定义变量max初始化为-0x7fffffff(一个很大的负数,0x是十六进制的开头,等于十进制的2147483647),以便让第一个数尽快替换max

求最大值的模拟过程:把1定为挑战者,1ffffffff80000001(HEX)/-2147483647(DEC)大,1为擂主。把8定为挑战者,81大,8为擂主。把9定为挑战者,98大,9为擂主。把4定为挑战者,4没有9大,9依然为擂主。把3定为挑战者,3没有9大,9依然为擂主。把10定为挑战者,109大,10为擂主。因此,在这些数中,10是最大的。

求最小值的模拟过程:把1定为挑战者,17fffffff(HEX)/2147483647(DEC)小,1为擂主。把8定为挑战者,8没有1小,1依然为擂主。把9定为挑战者,9没有1小,1依然为擂主。把4定为挑战者,4没有1小,1依然为擂主。把3定为挑战者,3没有1小,1依然为擂主。把10定为挑战者,10没有1小,1依然为擂主。因此,在这些数中,1是最小的。

代码实现(求最大值):

int n,max=-0x7fffffff; //一开始的擂主
cin>>n;
for(int i=1;i<=n;i++){
	int temp;
	cin>>temp;  //挑战者 
	if(temp>max){  //如果挑战者的值大于擂主的值 
		max=temp;  //挑战者成为新的擂主 
	}
}
cout<<max<<endl;  //最终的擂主就是最大值

代码实现(求最小值):

int n,min=0x7fffffff; //一开始的擂主
cin>>n;
for(int i=1;i<=n;i++){
	int temp;
	cin>>temp;  //挑战者 
	if(temp<min){  //如果挑战者的值小于擂主的值 
		min=temp;  //挑战者成为新的擂主 
	}
}
cout<<min<<endl;  //最终的擂主就是最小值

任务 7 7 7

七、保留几位小数

n n n 名同学在分 x m L xmL xmL 的肥宅快乐水,每名同学分到了多少毫升的肥宅快乐水?如果是 5 5 5 名同学分 500 m L 500mL 500mL 的肥宅快乐水,那么每名同学能分到 500 ÷ 5 = 100 ( m L ) 500\div5=100(mL) 500÷5=100(mL) 的快乐水,那么 3 3 3 名同学分 100 m L 100mL 100mL 的快乐水,每名同学就会分到 100 ÷ 3 = 100 3 ( m L ) 100\div3=\frac{100}{3}(mL) 100÷3=3100(mL) 的快乐水。程序不会那么智能,输出 100 3 \frac{100}{3} 3100 或者 33. 3 ˙ 33.\dot{3} 33.3˙ ,一般来说,题目会让我们保留几位小数(四舍五入)。

怎么实现保留几位小数呢?C++中,<iomanip>头文件为我们提供了保留几位小数的语句,能实现四舍五入保留小数位数的目的。其语句用法为cout<<fixed<<setprecision([保留的小数位数])<<[需要保留位数的变量];

比如我们要让 100 ÷ 3 100\div3 100÷3 的结果保留两位小数,怎么办哪,代码如下:

cout<<fixed<<setprecision(2)<<100/3<<endl;

这样的写法是错误的!程序会输出33.00而不是我们想要的33.33,因为10033都是int类型的常量,结果也是int类型,100/3的结果为33,再保留两位小数,结果就是33.00了。遇到这样的问题我们有两种解决办法:1.在100/3的前面加上一个(double),强制转换为double类型,这样就可以正确输出了。2.在100/3前面加上1.0*,这样会让double类型的常量1.010033doubleint做运算,都会隐式转移double类型。

注意!<<fixed<<setprecision(2)在整个程序中一直有效!**输出两个数 9.47854485 9.47854485 9.47854485 0.56666464 0.56666464 0.56666464 ,要求第一个数保留两位小数,对错代码分别如下(Assume that <iostream> and <iomanip> has been included):

错误:

cout<<fixed<<setprecision(2)<<9.47854485<<" "<<0.56666464<<endl;

正确(无法用现在的知识解决)(Assume that <cstdio> has been included):

printf("%.2lf ",9.47854445);
printf("%lf\n",0.56666464);

八、平均值算法

首先,输入一个正整数 n n n ,再输入 n n n 个整数 a 1 − a n a_1-a_n a1an ,求出 a 1 − a n a_1-a_n a1an 的平均值。

我们知道了求平均值的公式,假如数的个数为 x x x x x x 个数为 a 1 − a x a_1-a_x a1ax ,那么公式如下:

a 1 + a 2 + ⋅ ⋅ ⋅ + a x − 1 + a x x \LARGE{\frac{a_1+a_2+···+a_{x-1}+a_x}{x}} xa1+a2++ax1+ax

我们先输入正整数 n n n ,在定义double类型的 s u m sum sum ,利用求和模型求出 n n n 个数的和,最后输出 s u m ÷ n sum\div n sum÷n 的结果,按题目要求保留几位小数,这里默认保留 2 2 2 位。(整数和浮点数通用)

代码实现:

int n;
double sum=0;
cin>>n;
for(int i=1;i<=n;i++){
	double x;
	cin>>x;
	sum+=x;
}
cout<<fixed<<setprecision(2)<<sum/n<<endl;

三、动态规划(dp)讲义

敬请期待~~~

四、课后习题

1.完成计蒜客 循环的使用 思维拓展习题

2.完成洛谷循环结构入门题,题目如下:

声明:本讲义由 The YU Team Admin Wu yuyin 编撰,如需转载请得到 The YU Team 的管理员许可,并且附上此声明,否则将严肃处理。

主要参考:计蒜客课程内容-循环结构

Powered by The YU Team

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值