2024年寒假算法班集训day02-知识总结及题解(枚举)

1、寻找水仙花数-2837

在这里插入图片描述
题目描述了水仙花数的定义,并要求输出所有的三位水仙花数。水仙花数是指一个三位数,其各位数字立方和等于该数本身。

解题思路是穷举所有的三位数(100-999),对每一个数,分别计算其个位、十位和百位的数字,然后将这三个数字的立方和相加,检查它们的和是否等于原数。如果相等,就输出这个数。

代码实现了上述逻辑:

  1. 使用一个for循环遍历所有的三位数。
  2. 在每次循环中,用取余操作和整除操作分离出三位数的个位、十位和百位。
  3. 计算每个位上数字的立方和。
  4. 如果立方和等于原数,就输出这个数,并在输出的数之间加一个空格分隔。
#include<iostream>
using namespace std;
int main(){
	for(int i=100;i<1000;i++){
		int a=i%10;
		int b=i/10%10;
		int c=i/100;
		if(a*a*a+b*b*b+c*c*c==i)	cout<<i<<' ';
	}
	return 0;
}


代码的输出结果将是所有三位的水仙花数,每个数之间由一个空格隔开。

2、不高兴的津津-1252
在这里插入图片描述
题目描述了津津的周日程安排,并要求分析哪天津津会最不高兴。津津不高兴的条件是一天内上课时间超过8个小时。

代码实现了以下逻辑:

  1. 通过循环读入七天的日程安排,每天包括两个数字:在学校上课的时间和额外补习班的时间。
  2. 如果某一天的总上课时间超过8小时,则标记为不高兴的一天。
  3. 对于所有不高兴的天,比较哪一天上课时间最长,并记录下来。
  4. 如果存在不高兴的天,输出上课时间最长的那一天;如果津津整个星期都不会不高兴,输出0。
#include<iostream>
using namespace std;
int main(){
	int n,m,max1,sum=0;
	bool flag=true;
	for(int i=1;i<=7;i++){
		cin>>n>>m;
		if(n+m>8){
			flag=false;
			if(sum<n+m){
				sum=n+m;
				max1=i;
			}
		}
	}
	if(flag)	cout<<0;
	else	cout<<max1;
	return 0;
}

代码的输出是一个数字,代表津津最不高兴的那一天,用1至7表示周一到周日。如果有多天不高兴程度相同,则输出最早的那一天。如果津津每天的上课时间都不超过8小时,输出0。

3、安放地雷2-2844
在这里插入图片描述
题目要求找到一个矩阵中地雷的位置,并计算它能消灭的敌人数量。地雷能消灭它所在行和列的所有敌人。

代码流程如下:

  1. 输入矩阵的大小n
  2. 使用双层循环读入矩阵,并记录下地雷的位置(x, y)
  3. 再次遍历地雷所在的行和列,计算敌人的总数。
  4. 输出总共能消灭的敌人数量。
#include<iostream>
using namespace std;
int a[1001][1001];
int main(){
	int n,x,y;
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>a[i][j];
			if(a[i][j]==0){
				x=i;y=j;
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		if(a[x][i]==1)	ans++;
		if(a[i][y]==1)	ans++;
	}
	cout<<ans;
	return 0;
}

需要注意的是,由于地雷位置的敌人只会被计算一次,所以在计算时不需要考虑重复计数的情况。代码中没有考虑这一点,所以如果地雷位置上有敌人,程序会将其计算两次。此外,代码中也没有减去地雷所在位置可能的一个敌人(如果地雷位置上是敌人的话)。因此,如果地雷位置上是敌人,实际的敌人数应该是ans - 1

4、百钱买百鸡优化-2846
在这里插入图片描述
题目要求解决一个经典的数学问题,即“百钱买百鸡”问题。要求是用100钱买100只鸡,其中公鸡每只5钱,母鸡每只3钱,小鸡3只1钱,求公鸡、母鸡、小鸡各有多少只。

题解思路是使用穷举法,也就是枚举每种可能的鸡的组合,直到找到满足所有条件的解。代码中,两个for循环分别枚举了公鸡和母鸡的数量,小鸡的数量则由总数减去公鸡和母鸡的数量得出。

实现步骤如下:

  1. 枚举公鸡的数量,范围是0到20,因为公鸡最多只能买20只(超过20只就超过100钱)。
  2. 枚举母鸡的数量,范围是0到33,因为母鸡最多只能买33只(超过33只就超过100钱)。
  3. 计算剩余钱数能买多少只小鸡,小鸡的数量必须是3的倍数。
  4. 如果某种组合的总钱数等于100,并且鸡的总数也是100,则打印出该组合。
#include<bits/stdc++.h>
using namespace std;
int main() {
	for (int i=0;i<=20;i++) { //遍历公鸡的数量
		for (int j=0;j<=33;j++) { //遍历母鸡的数量
			int k=100-i-j; //遍历小鸡的数量
            if (i*5+j*3+k/3==100 && i+j+k==100 && k%3==0) {
                cout <<i<<" "<<j<<" "<<k<<endl;
            }
		}
	}
	return 0;
} 

代码的输出是所有可能的解,每个解一行,公鸡、母鸡和小鸡的数量用空格隔开。如果有多个解,公鸡数量少的排在前面。

5、棋盘问题-2847
在这里插入图片描述
题目要求计算在一个N×M的棋盘上,可以形成多少个正方形和多少个长方形(不包括正方形)。

题解思路是通过枚举左上角和右下角的所有可能点来计算正方形和长方形的数量。代码中使用了四个嵌套的循环来实现这个过程。其中,ij表示左上角的点,kl表示右下角的点。如果右下角的点在同一行或同一列上,即k-i == l-j,则形成的是正方形,否则形成的是长方形。

在给定的输入样例中,N=2,M=3,通过枚举所有可能的点对,我们可以得到8个正方形和10个长方形,这与样例输出一致。

代码的核心部分是:

#include<bits/stdc++.h>
using namespace std;
int main() {
	int m,n,z=0,c=0; //z用来记正方形个数,c来记长方形
	cin>>n>>m; //输入
	for (int i=0;i<=n;i++) { //遍历左上角点
		for (int j=0;j<=m;j++) {
			for (int k=i+1;k<=n;k++) { //遍历右下角点
				for (int l=j+1;l<=m;l++) {
					if (k-i==l-j) z++; //是正方形
					else c++; //是长方形
				}    
			}    
		}
	}
	cout<<z<<" "<<c; //输出
	return 0;   
} 

输出是正方形的数量和长方形的数量,用空格隔开。

6、添加运算符-1601
在这里插入图片描述
题目描述的是一个穷举搜索问题,即通过在四个给定的正整数之间插入运算符(+, -, *, /),找出所有可能的表达式计算结果等于给定值n的不同表达式的数量。

代码实现了以下逻辑:

  1. 读入四个整数以及目标值n。
  2. 使用三层嵌套循环遍历所有可能的运算符组合,即四个运算符每个都有四种可能。
  3. 对每一种运算符组合,从左到右计算表达式的值。
  4. 如果计算结果等于目标值n,则方法数加一。
  5. 输出所有可能的方法数。
#include<iostream>
using namespace std;
char ch[5]={'+','-','*','/'};//存储四种运算符
int compute(char x,int a,int b){//判断x运算符,返回运算结果
	switch(x){
		case '+':	return a+b;
		case '-':	return a-b;
		case '*':	return a*b;
		case '/':	return a/b;
	}
}
int main(){
	int a,b,c,d,n;//a,b,c,d表示四个整数 n:给定的值
	cin>>a>>b>>c>>d;
	cin>>n;
	int num,ans=0;//num:运算结果 ans:和n相等的式子个数
	for(int i=0;i<4;i++){//第一个运算符
		for(int j=0;j<4;j++){//第二个运算符
			for(int k=0;k<4;k++){//第三个运算符
				num=compute(ch[i],a,b);//第1个数与第2个数运算得到结果1
				num=compute(ch[j],num,c);//结果1与第3个数运算得到结果2
				num=compute(ch[k],num,d);//结果2与第4个数运算得到最终结果
				if(num==n)	ans++;//最终结果和n相等,ans累加1
			}
		}
	}
	cout<<ans;//结果和n相等的式子个数
	return 0;
}

具体的计算过程遵循题目描述的从左到右严格计算,不考虑运算符的优先级。例如,表达式1+2*3会被计算为(1+2)3,而不是1+(23)。

代码示例中,定义了一个compute函数来根据运算符和两个操作数返回计算结果,并在主函数中使用三层循环穷举所有可能性,通过调用compute函数计算最终结果并与目标值n比较,累加得到的方法数最终输出。

7、ABC-1703
在这里插入图片描述
题目描述了一个数学解密游戏,Elsie 有三个正整数 A、B、C,并告诉 Bessie 七个数字,宣称这些数字是 A、B、C 及它们各自的和(A+B,B+C,C+A 以及 A+B+C)的某种排列。任务是找出 A、B、C 的值。

代码实现了以下逻辑:

  1. 读取输入的七个数字并存储在数组 n[8] 中。
  2. 对数组进行排序,使得最小的数在数组的起始位置,最大的数在末尾。
  3. 根据排序,数组的第一个元素 n[0] 是 A,第二个元素 n[1] 是 B。
  4. 最大的数 n[6] 是 A+B+C 的和。
  5. C 可以通过 n[6](即 A+B+C)减去 A 和 B 得到,即 n[6] - n[0] - n[1]
  6. 输出 A、B、C 的值。
#include<bits/stdc++.h>
using namespace std;
int n[8]; //存储7个数字
int main(){
	for(int i=0;i<7;i++)	cin>>n[i];
	sort(n,n+7);//从小到大排序
	int a=n[0],b=n[1],c,abc=n[6];//a为最小数 b其次  abc为最大数
	c=abc-a-b;//c=(a+b+c)-a-b;
	cout<<a<<' '<<b<<' '<<c;//输出abc的值
	return 0;
}

通过排序,我们可以很容易地确定 A 和 B 的值,因为在所有可能的和中,A 和 B 必然是最小的两个数。然后我们可以利用最大数(即所有数的和)来确定 C 的值。由于题目保证了答案的唯一性,这种方法可以准确找到 A、B、C 的值。

8、回文日期-1283
在这里插入图片描述
题目要求计算在给定的两个日期之间,有多少个回文日期。一个日期被视为回文日期,如果它的8位数表示法(YYYYMMDD)从左到右读与从右到左读是相同的。

代码逻辑是这样的:

  1. 为了处理日期,代码中预设了一个数组 a,其中包含了每个月应有的天数,注意2月被设定为29天,这意味着需要在代码中单独处理闰年。
  2. 用户输入两个日期,存储在 nm 中。
  3. 代码遍历每个月和每一天。
  4. 对于每个可能的月份和日期,代码构造一个可能的日期数字 x
  5. x 是通过将月份和日期的个位和十位数颠倒,然后组合成年份的四位数,接着再加上原始的月份和日期来构造的。
  6. 如果构造出的日期数字 xnm 之间,那么它就是一个有效的回文日期。
  7. 最后,代码输出在这个范围内找到的回文日期数量。
#include<iostream>
using namespace std;
int a[13]={0,31,29,31,30,31,30,31,31,30,31,30,31}; 
// 0  1  2  3  4  5  6  7  8  9  10  11 12
int main(){
	int n,m,ans=0;//ans在n和m之间,有多少回文日期 
	cin>>n>>m;
	for(int i=1;i<=12;i++){//月份 
		for(int j=1;j<=a[i];j++){//当月的天数 
			int x=j%10*1000+j/10*100+i%10*10+i/10;	
			x=x*10000;
			x=x+i*100+j;
			if(x>=n && x<=m)	ans++;
		}
	} 
	cout<<ans;
	return 0;
}

代码中没有考虑到闰年2月份只有28天的情况,这可能会在计算中产生错误。此外,对于所有的年份来说,代码假定2月都有29天,这也不正确。正确的逻辑是对于每个年份分别判断是否为闰年,并据此确定2月的天数。闰年的条件是年份能被400整除,或能被4整除但不能被100整除。

9、三角牧场-1704
在这里插入图片描述
题目描述了一个在二维平面上的问题,要求在N个给定的点中选择三个点构成一个三角形,这个三角形的一边必须与x轴平行,另一边与y轴平行。我们要找出可以构成的最大面积。

题解思路如下:

  1. 首先,读取所有N个点的坐标。
  2. 接下来,我们需要找出所有可能的三角形组合。因为三角形的一条边必须与x轴平行,另一条边必须与y轴平行,所以我们实际上是在寻找两个点,它们的x坐标或y坐标相同。
  3. 对于任意两个有相同x坐标或y坐标的点,第三个点必须在这两点形成的矩形对角线上。这个矩形的长和宽就是三角形的两个边长。
  4. 计算每个这样的三角形的面积,取最大值。
  5. 输出最大面积的两倍(因为题目要求输出面积的两倍)。
#include<bits/stdc++.h>
using namespace std;
struct node{
	int x,y;// x:x轴坐标 y:y轴坐标
}a[101];// 存储点的坐标
int main(){
	int n,max1=0;//n:n个点 max1:最大面积
	cin>>n;
	for(int i=1;i<=n;i++)	cin>>a[i].x>>a[i].y;
	for(int i=1;i<=n;i++){//第一个点
		for(int j=1;j<=n;j++){//第二个点
			for(int k=1;k<=n;k++){//第三个点
				if(i==j || j==k ||i==k)	continue;//寻找三个不同坐标的点
				if(a[i].x==a[j].x && a[i].y==a[k].y)//判断是否平行x轴和平行y轴
					max1=max(max1,abs(a[i].x-a[k].x)*abs(a[i].y-a[j].y));//计算面积,最大面积赋值给max1
			}
		}
	}
	cout<<max1;//输出最大面积
	return 0;
}

代码实现这个思路时,可能会通过两层循环遍历所有点的组合,并计算出所有可能的三角形的面积,再找出最大值。这里注意到只有当我们找到一对点的x坐标或y坐标相同时,我们才需要进一步寻找第三个点来形成三角形。最后,比较所有找到的三角形的面积,取最大值并输出它的两倍。

10、海港-1284
在这里插入图片描述
题目描述了一个海港接待船只的场景,每艘船都有其到达时间和乘客信息,包括乘客的国籍。小 K 想要知道,在每艘船到达时,过去24小时内(86400秒内)共有多少个不同国家的乘客到达海港。

题解的思路是:

  1. 创建一个数据结构来存储每个乘客的到达时间和国籍。
  2. 对于每艘船的到达,记录下它的到达时间和船上的每个乘客的国籍,同时更新一个记录国籍数量的数组。
  3. 遍历之前的记录,如果记录中的时间早于当前船只到达时间24小时之前的,那么从统计中减去相关的国籍。
  4. 对于每艘船的到达,输出过去24小时内不同国籍的数量。
#include<iostream>
using namespace std;
const int maxx=100001,maxk=300001;
struct data{
	int t,g;//t:时间 g:国籍
}a[maxk];//存储乘客信息
int num[maxx];//统计国籍数据
int t,k,g,n,x=0,p=0,q=0;//t:当前船到达时间 k:当前船上人数 g:国籍
//p,q用以标记乘客编号
int main(){
	cin>>n;
	for(int i=0;i<n;i++){//模拟n艘船到港的情况
		cin>>t>>k;
		for(int j=0;j<k;j++){//循环将每位乘客的信息存入
			cin>>g;
			a[q].t=t;	a[q].g=g;
			q++;	num[g]++;
			//先默认统计所有国家
			if(num[g]==1)	x++;
		}
		while(a[p].t<=t-86400){//将不在前24小时内的国家去掉
			num[a[p].g]--;
			if(num[a[p].g]==0)	x--;
			p++;
		}
		cout<<x<<endl;
	}
	return 0;
}

代码实现会首先初始化必要的变量和数组,然后逐行读取输入数据,对每艘船的每个乘客进行处理,并适时更新统计信息。最后,每当一艘船到达时,程序将输出到那一刻为止,过去24小时内到达海港的不同国籍的总数。

  • 21
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值