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即可

posted @   banyanrong  阅读(74)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示