目录
0、枚举 简介
枚举是基于已有知识来猜测答案的一种问题求解策略。枚举的思想是不断地猜测,从可能的集合中一一尝试,然后再判断题目的条件是否成立。
要点
- 给出解空间
建立简洁的数学模型。
枚举的时候要想清楚:可能的情况是什么?要枚举哪些要素?- 减少枚举的空间
枚举的范围是什么?是所有的内容都需要枚举吗?
在用枚举法解决问题的时候,一定要想清楚这两件事,否则会带来不必要的时间开销。- 选择合适的枚举顺序
根据题目判断。比如例题中要求的是最大的符合条件的素数,那自然是从大到小枚举比较合适。
1、洛谷 P2241 统计方形(数据加强版)
oj:https://www.luogu.com.cn/problem/P2241
package 暴力枚举;
import java.util.Scanner;
public class P2241统计方形 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n=in.nextInt();
int m=in.nextInt();
long zheng=0,juXing=0;//int:+-2.1*10^9;long:+-9.2*10^18;long才能accept 100%
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
zheng+=Math.min(i, j);
}
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
juXing+=i*j;
}
}
System.out.println(zheng+" "+(juXing-zheng));
}
}
/*
一、算正方形的个数
1.如果我们固定了正方形的右下角(i,j),你能不能算出此时可能的正方形的个数?
2.显然,此时答案为Min(i,j).
3.所以可以枚举右下角,计算此时答案,求和即可。
二、算长方形个数
1.其实算长方形并不常见,但算矩形大家应该经常遇到,所以如果你会算矩形,再联系第一个问题,
那答案就转化为 矩形个数-正方形个数.
2.像求解正方形个数一样,固定矩形右下角(i,j),显然此时矩形个数为i*j.
3.同理,求和即可.
*/
2、洛谷 P3392 涂国旗
oj:https://www.luogu.com.cn/problem/P3392
package 暴力枚举;
import java.util.Scanner;
public class P3392涂国旗 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n=in.nextInt();
int m=in.nextInt();
char[][] arr=new char[n][m];
String s = null;
int cnt=0,k,g,ans=2500;//ans初始化成一个很大的数
for(int i=0;i<n;i++) {//因为没有直接输入char[][]的next(),所以转换为输入字符串
s=in.next();
arr[i]=s.toCharArray();//将输入字符串转换为数组,即第i行数
}
for(int i=0;i<n-2;i++) {//由于白色下面还有蓝色和红色,所以i(白与蓝的边界)枚举到(n-3)
for(int j=i+1;j<n-1;j++) {//j(蓝与红的边界)至少要比i大1,同理枚举到(n-2),这样可以减少枚举次数
cnt=0;
//壮观地枚举三个区域
for(k=0;k<=i;k++)for(g=0;g<m;g++)if(arr[k][g]!='W')cnt++;
for(k=i+1;k<=j;k++)for(g=0;g<m;g++)if(arr[k][g]!='B')cnt++;
for(k=j+1;k<=n-1;k++)for(g=0;g<m;g++)if(arr[k][g]!='R')cnt++;
ans=Math.min(ans,cnt);//更新答案
}
}
System.out.println(ans);
}
}
3、 Java 大学B 组试题D: 数的分解
第十届蓝桥杯大赛软件类省赛 本题总分:10 分
【问题描述】
把2019 分解成3 个各不相同的正整数之和,并且要求每个正整数都不包含数字2 和4,一共有多少种不同的分解方法?注意交换3 个整数的顺序被视为同一种方法,例如1000+1001+18 和1001+1000+18 被视为同一种。
【答案提交】这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
思路:主要还是考虑到不同顺序的三个数只能算一种,所以可以i从1~2019,j从i+1到2019,k从j+1到2019,这样i,j,k三个数就是呈递增顺序来遍历就不存在重复问题了。
package javaB省赛2019;
import java.util.Scanner;
//思路:因为要求3个各不相同的正整数的分解方法。
//i,j,k升序排序肯定不同,依次取i,j,k;且复杂度小
public class D数的分解 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int k,cnt=0;
for(int i=1;i<=2016;i++) {
for(int j=i+1;j<=2016;j++) {
k=2019-i-j;
if(k<=0)break;
if(k>j&&isOk(i)&&isOk(j)&&isOk(k)) {
System.out.println(i+" "+j+" "+k);
cnt++;
}
}
}
System.out.println(cnt);
}
//判断某数是否包含数字2 和4
static boolean isOk(int n) {
if(n/1000==2||n/1000==4)return false;
else if(n/100%10==2||n/100%10==4)return false;
else if(n/10%10==2||n/10%10==4)return false;
else if(n%10==2||n%10==4)return false;
else return true;
}
}
输出: