二、枚举法

枚举,故名思意,是一种把所有情况都列举出来,然后在所有情况中找到需要的答案,看似简单但是也需要加以思考

1、找出质数

如果一个数不能被自己和1以外的数字整除,那这个数就是质数。
找出1~ n中的所有质数,两个数之间用括号隔开 10 ≤ n ≤ 100000 10 \le n\le 100000 10n100000.

输入样例 #1
15
输出样例 #1
2 3 5 7 11 13

这个题非常简单,我们只需要从一开始枚举每一个数字,依次判断这个数是不是质数,如果是的话就把他输出即可。
answer:

#include<bits/stdc++.h>  
using namespace std;  
bool func(int n){  
	if(n == 1)return false;  
	for(int i = 2; i * i<= n; i++){  
		if(n % i == 0)return false;  
	}  
	return true;  
}  
int main(){  
	int n; cin >> n;  
	for(int i = 1; i <= n; i++){  
		if(func(i)){  
			cout << i << " ";  
		}  
	}  
	return 0;  
}

2、漆房

包租公A有一条很长的走廊,走廊上并排着很多房间,每个房间的住户都把自己门口的一块地涂成了自己喜欢的颜色,每种颜色用一个整数n来表示(1≤n≤60)。现在A想用一种颜色把整条走廊给刷成一种颜色,A每天只能刷完k间房的门口,请你输出A至少几天才能让走廊统一色号。

输入格式

一个整数n,表示走廊长度,输入一个整数k,表示一天能刷多长。
随后输入n个整数,每个表示每个房间门口的颜色。

输出格式

一个整数,表示最少使用多少天。

输入样例 #1
6 2
1 1 1 2 2 1
输出样例 #1
1
解释

如果全部用1颜色刷的话,一天就能把2-2段给覆盖完,如果用2颜色的话,则需要三天,所以输出1.
由于数据量较小,我们可以直接根据题意来枚举所有情况。

#include<bits/stdc++.h>  
using namespace std;  
int room[1000];  
int main(){  
	int n, k;  
	cin >> n >> k;  
	for(int i = 1; i <= n; i++){  
		cin >> room[i];  
	}  
	int minn = 99999;  
	for(int i = 1; i <= 60; i++){  
		//枚举所有颜色  
		if(minn == 0)break;  
		int cnt = 0;  
		for(int j = 1; j <= n; j++){  
			if(room[j] != i){  
			//如果颜色不一样就开始刷,即跳过这部分的走廊  
				cnt++;  
				j += k - 1;  
				//因为结束后for循环会给j再加1,所以只要加上k-1即可  
			}  
		}  
		minn = min(cnt, minn);  
	}  
	cout << minn;  
	return 0;  
}

3、最大乘积

输入若干组 n n n个数组成的序列, 你需要找出一段连续的乘积最大的子序列,如果这个最大的序列的乘积S不是正数,则输出“无解”。 ( 1 ≤ n ≤ 18 , − 1 0 9 ≤ S ≤ 1 0 9 ) (1 \le n \le 18, -10^9 \le S \le 10 ^9) (1n18,109S109).

输入样例 #1
3
2 4 -3
5
2 5 -1 2 -1
输出样例 #1
8
20

因为此题n较小,所以可以只枚举始末位置,然后逐个相乘即可,这样的复杂度为 n 3 n^3 n3,如果n较大的话,直接枚举则不可取,所以考虑优化。
还记得前缀和吗?我们在前缀和的基础上进行改良即可得到一个新数组:前缀积。

与前缀和类似,我们现在以a[i]记录数字(从a[1]开始),以pre[i]来记录从a[1]连乘到a[i]的值
则:从a[n] 连城到 a[m] 的值则是pre[m] / pre[n - 1]。特别的,我们需要讲pre[0]初始化为1.

这样的话我们就能只用枚举起始位置,并且不用每次枚举都要连乘一遍。复杂度为 n 2 n^2 n2.

#include<bits/stdc++.h>  
using namespace std;  
void solve(int n){  
	long long pre[n + 3];  
	for(int i = 1; i <= n; i++){  
		cin >> pre[i];  
		pre[i] = pre[i - 1] * pre[i];  
	}  
	long long maxx = -9999999;  
	for(int i = 0; i < n; i++){  
		for(int j = i + 1; j <= n; j++){  
			maxx = max(pre[j] / pre[i], maxx);  
		}  
	}  
	if(maxx >= 0)cout << maxx << endl;  
	else cout << "无解" << endl;  
}  
int main(){  
	int n;  
	while(cin >> n){  
		solve(n);  
	}  
	return 0;  
}

4、除法

输入任意正整数k,按从小到大的顺序输出所有满足 a b c d e / f g h i j = n abcde/fghij = n abcde/fghij=n的表达式,其中 a a a$j$恰好是$0$ 9 9 9的一个排列,即 a b c d f e g h i j abcdfeghij abcdfeghij是不重复的单个数字(可包含前导零)。 2 ≤ n ≤ 79 2 \le n \le 79 2n79.

输入样例 #1
62
输出样例 #1
79546 / 01283 = 62
95736 / 01528 = 62

这一题要枚举0~9的全排列然后来配对出 abcde 和 fghij 的所有情况吗?想一下,全排列一共有 10 ! 10! 10!种,这个数据量太大了。我们可以通过枚举 fghij,然后用 figij 来 算出 abcde 。然后判断每一位的数字会不会重复,然后在两个数加起来超过十位时终止枚举即可。
to_string 是把数字转化为字符串。我们每次把 fghij 转换成 s1,把 abcde 转化为 s2。然后把两个字符串组合,根据字符串的长度来判断是否要结束枚举,如果加起来的字符长度为9,那可能是缺少前导0,所以我们给他补上一个0。

#include<bits/stdc++.h>  
using namespace std;  
int func(int n, int m){  
	string s1 = to_string(n);  
	string s2 = to_string(m);  
	s1 = s1 + s2;  
	if(s1.size() > 10 || s2.size() > 5)return 3;  
	if(s1.size() < 9)return 1;  
	if(s1.size() == 9)s1 = s1 + '0';  
	set<char>s;  
	for(int i = 0; i < 10; i++){  
		s.insert(s1[i]);  
	}  
	if(s.size() == 10)return 2;  
	else return 1;  
}  
int main(){  
	int n;  
	cin >> n;  
	for(int i = 1000; ;i++){// fghij 可以是四位数,并且最小是能是四位数  
		int j = i * n;  
		int t = func(i, j);  
		if(t == 1)continue;  
		else if(t == 3)break;  
		else if(t == 2){  
			printf("%05d / %05d = %d\n",j, i, n);  
		}  
	}  
	return 0;  
}

5、分数拆分

输入若干组数字,每组一个正整数k,找出所有的正整数 x > = y . x >= y. x>=y.使得 1 k = 1 x + 1 y . \displaystyle\frac{1}{k} = \displaystyle\frac{1}{x} + \displaystyle\frac{1}{y}. k1=x1+y1.

输出格式

一个数字n,表示满足要求的组数,随后n行,按y从小到大输出每一组

输入样例 #1
2
12
输出样例 #1
2
1 / 2 = 1 / 6 + 1 / 3
1 / 2 = 1 / 4 + 1 / 4
8
1 / 12 = 1 / 156 + 1 / 13
1 / 12 = 1 / 84 + 1 / 14
1 / 12 = 1 / 60 + 1 / 14
1 / 12 = 1 / 48 + 1 / 16
1 / 12 = 1 / 36 + 1 / 18
1 / 12 = 1 / 30 + 1 / 20
1 / 12 = 1 / 28 + 1 / 21
1 / 12 = 1 / 24 + 1 / 24

由于除法的精度损,我们尽量把除法转化成乘法。
  由 1 k = 1 x + 1 y → k x + k y = x y     即: x ( y − k ) = k y 由\displaystyle\frac{1}{k} = \displaystyle\frac{1}{x} + \displaystyle\frac{1}{y} → kx + ky = xy\ \ \ \ 即:x(y - k) = ky k1=x1+y1kx+ky=xy    即:x(yk)=ky
因为 y 可以远小于 x,所以我们应该用 y 去推 x,那什么时候停止推算呢? 
因为 x > = y → 1 x < = 1 y 因为x >= y → \displaystyle\frac{1}{x}<=\displaystyle\frac{1}{y} 因为x>=yx1<=y1
这样的的话, 1 k = 1 x + 1 y → 1 k − 1 x = 1 y 这样的的话,\displaystyle\frac{1}{k} = \displaystyle\frac{1}{x} +\displaystyle\frac{1}{y}→\displaystyle\frac{1}{k} - \displaystyle\frac{1}{x} = \displaystyle\frac{1}{y} 这样的的话,k1=x1+y1k1x1=y1
即: 1 k − 1 y < = 1 y , 即: 1 k < = 2 1 y ; 即 2 k > = y 即:\displaystyle\frac{1}{k} - \displaystyle\frac{1}{y} <=\displaystyle\frac{1}{y}, 即:\displaystyle\frac{1}{k} <= 2\displaystyle\frac{1}{y}; 即2k >= y 即:k1y1<=y1,即:k1<=2y1;2k>=y
这样的话我们只需要把y枚举到2k即可。
因为要先输出组数,再输出每组内容,所以可以使用一个不定长数组来解决。

#include<bits/stdc++.h>  
using namespace std;   
void solve(int k) {  
	vector<int>x, y;  
	for(int i = 1; i <= 2 * k; i++){  
		if(i <= k)continue; //分母不能为0和复数  
		if(k * i % (i - k) == 0){  
			int j = k * i / (i - k);  
			x.push_back(j);  
			y.push_back(i);  
		}  
	} 
	cout << x.size() << endl;  
	for(int i = 0; i < x.size(); i++){  
		printf("1 / %d = 1 / %d + 1 / %d\n", k, x[i], y[i]);  
	}  
}  
int main(){  
	int k;  
	while(cin >> k){  
		solve(k);  
	}  
	return 0;  
}
  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fanxinfx2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值