算法学习笔记——暴力求解之枚举
文章目录
枚举
枚举是指对每个可能的解进行逐一判断,直到找到符合题目要求的答案。枚举类的题目本身并不复杂,但在采取枚举策略之前,一定要好好的分析题目的枚举量,枚举量过大的时候,需要选择其他的解决方法。即使问题适合枚举,也要进行分析,以便通过减少部分无效的枚举来使程序更加的简洁和高效。
例题
一、abc(清华大学复试上机题)
题目
三重循环解法
#include <iostream>
#include<cstdio>//标准输入输出,相当于stdio.h
using namespace std;
int main() {
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
for (int k = 0; k <= 9; k++) {
if (100*i+110*j+12*k == 532) {
printf("%d %d %d\n",i,j,k);
}
}
}
}
}
二、反序数(清华大学复试上机题)
题目
一重循环解法
#include <iostream>
using namespace std;
int R(int x){//求反序数
int revx=0;
while(x!=0){
revx *= 10;
revx += x%10;
x/=10;
}
return revx;
}
int main() {
for(int i=1000;i<=9999;i++){
if(i*9==R(i)){
printf("%i\n",i);
}
}
}
// 64 位输出请用 printf("%lld")
四重循环解法
#include <iostream>
using namespace std;
int main() {
int a, b, c, d;
for (int a = 1; a <= 9; a++) {
for (int b = 0; b <= 9; b++) {
for (int c = 0; c <= 9; c++) {
for (int d = 0; d <= 9; d++) {
int num1 = 1000 * a + 100 * b + 10 * c + d;
int num2 = 1000 * d + 100 * c + 10 * b + a;
if (9*num1 == num2) {
printf("%d\n", num1);
}
}
}
}
}
}
// 64 位输出请用 printf("%lld")
三、对称平方数1(清华大学复试上机题)
题目
解法
#include <iostream>
#include <cmath>
using namespace std;
int R(int x) {
int revx = 0;
while (x != 0) {
revx *= 10;
revx += x % 10;
x /= 10;
}
return revx;
}
int main() {
for (int i = 0; i <= 256; i++) {
if (pow(i,2) == R(pow(i,2))) {
printf("%d\n", i);
}
}
}
// 64 位输出请用 printf("%lld")
补充知识(cmath库)
#include <cmath>
pow(a,b) //a的b次方
sqrt(x) //x的开平方,根号下的x
abs(n) //整数n的绝对值
fabs(m) //浮点数m的绝对值
习题
一、与7有关的数
题目
我的解法
#include<iostream>
using namespace std;//cin,cout函数
int isseven(int n) {
int m = n;
if (n <= 0) {
return false;
}
while (n != 0) {
if (m % 7 == 0 || n % 10 == 7) {
return true;
}
n /= 10;
}
return 0;
}
int main() {
int a, sum = 0;
cin >> a;
for (int i = 0; i <= a; i++) {
if (isseven(i) == false) {
sum += i * i;
}
}
printf("%d\n", sum);
}
更好的解法
#include <stdio.h>
#include <math.h>
int main()
{
int n,sum=0;
scanf("%d",&n);
for(int i=0;i<=n;i++)
if((i%7)&&i%10!=7&&i/10!=7)
sum+=pow(i,2);
printf("%d\n",sum);
return 0;
}
二、百鸡问题
题目
我的解法
#include<iostream>
using namespace std;
int main(){
float n=0;
cin>>n;
for(int i=0;i<=100;i++){
for(int j=0;j<=100;j++){
for(int k=0;k<=100;k++){
float sum=i*15+9*j+k;//为了解决小数的问题,这样写代码
if(sum<=3*n&&i+j+k==100){
printf("x=%d,y=%d,z=%d\n",i,j,k);
}
}
}
}
}
三、Old Bill
题目
解法
//在祖父的文件中发现了一张帐单。72只火鸡$_679_显然代表这些火鸡总价的数字的第一位和最后一位在这里被空白(表示为_)取代,
//因为它们褪色且难以辨认。两个褪色的数字是多少?一只火鸡的价格是多少?
//我们想编写一个程序来解决上述问题的一般版本。N只火鸡$_XYZ_火鸡的总数N在1到99只之间,包括两者。
//总价最初由五位数组成,但我们只能看到在中间的三位数。我们假设第一个数字是非零的,
//一只火鸡的价格是整数美元,所有火鸡的价格都是相同的。给定N、X、Y和Z,编写一个程序来猜测两个褪色的数字和原始价格。
//如果原始价格有多个候选者,则输出应该是最昂贵的一个。
#include <iostream>
#include <cstdio>
using namespace std;
int main(){
int n, x, y, z;//n火鸡数、xyz原价格中间三位
while(~scanf("%d", &n)){
//scanf()是有返回值的,如果遇到错误或遇到end of file,返回值为EOF,EOF值一般在宏定义中为-1,-1二进制取反即为0(假),可用于结束循环
scanf("%d %d %d", &x, &y, &z);
int tot, f = 0;//tot原价格、f标记是否存在能够整除火鸡数n的价格
//这里选择从9枚举到1是为了第一次输出就是最高价格
for(int a = 9; a >= 1; a--){//a控制原价格的万位[1,9]
for(int b = 9; b >= 0; b--){//b控制原价格的个位[0,9]
tot = a * 10000 + x * 1000 + y * 100 + z * 10 + b;
if(tot % n == 0){//如果原价格tot能够整除火鸡数n
f = 1;//则将整除标记置1
printf("%d %d %d\n", a, b, tot / n);
break;
}
}
if(f) break;//如果已经整除,则跳出枚举
}
if(!f) printf("0\n");//如果没有可以整除的价格,则打印0
}
return 0;
}