7.1 简单枚举
第七章主要讲述暴力求解法
许多问题都可以暴力解决--不用动太多脑筋,把所有可能性都列举出来,然后一一试验,尽管这样的方法看起来显得很“笨”,但却常常是行之有效的
在枚举复杂对象之前,先尝试着枚举一些相对简单的内容,如整数,子串等,尽管暴力枚举不用太动脑筋,但对问题进行一定的分析往往会让算法更加简洁,高效(常见剪枝)
Division
暴力枚举即可(doge
点击查看笔者代码
#include<iostream>
using namespace std;
const int base = 100000;
int main() {
int n, cnt = 0;
while(scanf("%d", &n) == 1 && n) {
if(cnt++) cout << endl;
int sign = 1;
for(int i = 1234; n*i < base; i++) {
if(n < base/10 && n*i < base/10) continue;
int flag = 0;
bool num[10] = {0};
int n1 = i, n2 = n*i;
while(n1) {
if(num[n1%10]) {
flag = 1;
break;
}
num[n1%10] = 1;
n1 = n1/10;
}
if(flag) continue;
while(n2) {
if(num[n2%10]) {
flag = 1;
break;
}
num[n2%10] = 1;
n2 = n2/10;
}
for(int j = 1; j < 10; j++) {
if(!num[j]) {
flag = 1;
break;
}
}
if(flag) continue;
sign = 0;
printf("%05d / %05d = %d\n", n*i, i, n);
}
if(sign) cout << "There are no solutions for " << n << "." << endl;
}
return 0;
}
枚举0-9所有排列,没这个必要,只需要枚举fghij就可以算出abcde,然后判断是否所有数字都不相同即可,不仅程序简单,而且枚举量也从10!=3628800降低至不到1万,而且当abcde和fghij加起来超过10位时可以终止枚举,这边的应该是指有人到达六位数就不可以了?,感觉有点矛盾。由此可见,即使采用暴力枚举,也是需要认真分析问题的
Maximum_Product
点击查看笔者代码
#include<iostream>
using namespace std;
const int maxn = 20;
int val[maxn];
long long value(int s, int e) {
long long temp = -1;
for(int i = s; i < e; i++) {
if(i==s) temp = val[i];
else temp *= val[i];
}
return temp;
}
long long getVal(int m, int n) {
int cnt = 0, s = -1, t = -1;
long long ans = -1;
for(int i = m; i < n; i++)
if(val[i] < 0) {
if(s == -1) s = i;
t = i;
cnt++;
}
if(cnt%2) {
if(n-m==1) ans = val[m];
else{
ans = -1;
if(value(m, s) > ans) ans = value(m, s);
if(value(s+1, n) > ans) ans = value(s+1, n);
if(value(m, t) > ans) ans = value(m, t);
if(value(t+1, n) > ans) ans = value(t+1, n);
}
}else{
if(m < n) ans = 1;
for(int i = m; i < n; i++) ans *= val[i];
}
return ans;
}
int main() {
int n, kase = 0;
while(scanf("%d", &n)==1) {
for(int i = 0; i < n; i++) scanf("%d", &val[i]);
cout << "Case #" << ++kase << ": The maximum product is ";
long long ans = -1, temp;
int s = 0;
for(int i = 0; i < n; i++) {
if(val[i] == 0) {
temp = getVal(s, i);
if(temp > ans) ans = temp;
s = i+1;
}
}
temp = getVal(s, n);
if(temp > ans) ans = temp;
cout << ((ans <= 0) ? 0 : ans) << "." << endl << endl;
}
return 0;
}
好吧,笔者前面迫害严重,不敢写的过于奔放,本题可以直接硬枚举,时间上是宽裕的,可以不用进行优化
连续子序列有两个要素:起点和终点,因此只需枚举起点和终点即可。由于每个元素的绝对值不超过10且不超过18个元素,最大可能的乘积不会超过10**18,可以用long long存储。
Fractions_Again
点击查看代码
#include<cstdio>
#include<cmath>
using namespace std;
const double efs = 1e-18;
const int maxn = 10000 + 10;
int ans[maxn][2];
int main() {
int n;
while(scanf("%d", &n) == 1) {
int cnt = 0;
for(int i = n+1; i <= 2*n; i++)
for(int j = n*i/(i-n)-1; ; j++) {
if(abs((double)1/i+(double)1/j-(double)1/n) <= efs) {
ans[cnt][0] = j;
ans[cnt++][1] = i;
break;
}
if((double)1/n-(double)1/i-(double)1/j > efs) break;
}
printf("%d\n", cnt);
for(int i = 0; i < cnt; i++) printf("1/%d = 1/%d + 1/%d\n", n, ans[i][0], ans[i][1]);
}
return 0;
}
本题主要是找到循环的关键,也就是通过样例发现y的值是(k,2k]之间的,然后通过x = yk/(y-k)来近似加速x的值的获得,注意有时候可能并不存在x,所以需要特判,然后就是浮点误差的问题了因为k最多可以到10000,因此k2=100000000=18,这边的精度需要到达1e-15以后,这个就是本题笔者写的最大问题,难以量化,只能凭感觉去猜测
这边作者的提示也是根据y尝试计算出x即可
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)