暴力算法(volence’s beautify of algorithm)
- 思想:利用暴力法的思想找到所有的解,然后从中选出符合问题要求的解
- 算法总结:暴力法的优点是实现简单,容易编程,但是往往会消耗更多的时间和空间资源,因此大多数暴力法还要根据应用背景尽力改进
左 | 右 |
---|---|
找到问题的所有的解 | 筛选出符合题意的解 |
- 全排列问题:
给定数据k,请依照样例,输出其全排列
思路:设置一个数组来存储1-k的数字,然后再设置一个数组记录每个数字的访问情况,
最后用一个栈来记录访问的路径,再依次深度递归,并修改标记,递归回程时恢复标记,
如果栈的大小大于k则输出此次排列,直到递归到所有的子树
样例1:
3
输出:
123
132
213
231
312
321
样例2:
4
输出:
1234
1243
1324
1342
1423
1432
2134
2143
2314
2341
2413
2431
3124
3142
3214
3241
3412
3421
4123
4132
4213
4231
4312
4321
代码如下:
思路:设置一个数组来存储1-k的数字,然后再设置一个数组记录每个数字的访问情况,
最后用一个栈来记录访问的路径,再依次深度递归,并修改标记,递归回程时恢复标记,
如果栈的大小大于k则输出此次排列,直到递归到所有的子树
样例1:
3
输出:
123
132
213
231
312
321
样例2:
4
输出:
1234
1243
1324
1342
1423
1432
2134
2143
2314
2341
2413
2431
3124
3142
3214
3241
3412
3421
4123
4132
4213
4231
4312
4321
代码如下:
import java.util.Scanner;
// Created by Chenglong Shi on 2021/10/19.
// Only can use to study
// Once found commercial or illegal use will be pursued to the end
// Banning plagiarism
// Email:2230307855@qq.com
// 内部可能含有拼音和汉语注释
// by 史成龙
// 方法:
//
public class AllPermutation {
static final int ma=10;
static int n,top=0;
static int []a=new int[ma];
static int []st=new int[ma];
static int []vis=new int[ma];
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
n=in.nextInt();
for(int i=0;i<n;i++) a[i]=i+1;
getPermutation(1);
in.close();
}
public static void show(){
for(int i=0;i<top;i++) System.out.print(st[i]);
System.out.println();
}
public static void getPermutation(int floor){
if(floor>n){
show();
return;
}
for(int i=0;i<n;i++){
if(vis[i]==0){
st[top++]=a[i];
vis[i]=1;
getPermutation(floor+1);
top--;
vis[i]=0;
}
}
}
}
- 快速幂问题:
给定数据a和b在给定时间内输出a的b次方
思路:用递归的方式编程,用long类型来存储数据,每次将b折半,直到b的值为1的时候,返回a的值,然后在每次回溯中判断b是偶数还是奇数,如果是偶数则返回上一层函数返回的值的平方,否则返回上一层值的平方乘以a。当回溯完毕后返回的就是a的b的次方
样例1:
3 8
输出
6561
样例2:
2 4
输出:
16
代码如下:
// Created by Chenglong Shi on 2021/10/16.
// Only can use to study
// Once found commercial or illegal use will be pursued to the end
// Banning plagiarism
// Email:2230307855@qq.com
// 内部可能含有拼音和汉语注释
// by 史成龙
// 方法:递归
//
import java.util.Scanner;
public class fast_power {
private static long a;
private static long b;
public static void main(String[] args) {
Scanner in =new Scanner(System.in);
while(in.hasNext()){
a=in.nextLong();
b=in.nextLong();
System.out.println(fast_power(b));
}
in.close();
}
public static long fast_power(long b){
if(b<=1) return a;
long temp=fast_power(b/2);
if(b%2==0) return temp*temp;
else return temp*temp*a;
}
}
- 幂集问题
输入一个数k,输出集合元素为1-k的集合的子集
思路:用二进制的方式每次测试0-2的k次方的相于运算的结果,如果相与的结果大于等于0,则表示此时相与元素是当前目标集合的元素,循环结束后即可输出所有的子集,同时使用二进制的方式可以加速程序的运行
输入样例1:
3
输出:
{}
{1}
{2}
{3}
{1,2}
{1,3}
{2,3}
{1,2,3}
输入样例2:
2
输出:
{}
{1}
{2}
{1,2}
代码如下:
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
// Created by Chenglong Shi on 2021/10/16.
// Only can use to study
// Once found commercial or illegal use will be pursued to the end
// Banning plagiarism
// Email:2230307855@qq.com
// 内部可能含有拼音和汉语注释
// by 史成龙
// 方法:二进制获得幂集
// Copyright (c) 2021 幂集的获得. All rights reserved.
//
public class pow_set {
private static int n,index=1;
static final int ma=1080;
static String []result=new String[ma];
public static void main(String[] args) {
for(int i=0;i<ma;i++) result[i]="-";
Scanner in=new Scanner(System.in);
n=in.nextInt();
int len=(int)Math.pow(2,n);
getsq();
Arrays.sort(result,1,len, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
String k1=(String) o1,k2=(String) o2;
if(k1.length()==k2.length()) return k1.compareTo(k2);
else return k1.length()-k2.length();
}
});
show(len);
in.close();
}
public static void getsq(){
for(int i=0;i<(1<<n);i++){
String m="{";
for(int j=0;j<n;j++){
if((i&(1<<j))>0)
{
// System.out.println("j is:"+j);
if(m.length()==1) m+=String.valueOf(j+1);
else m+=(","+String.valueOf(j+1));
}
}
m+="}";
// System.out.print("m is:"+m);
// System.out.println("---------------");
result[index++]=new String(m);
}
}
public static void show(int len){
for(int i=1;i<=len;i++)
if(result[i].length()>0){
System.out.println(result[i]);
}
}
}
- n皇后
输入n,代表n个皇后,放置的规则是每个皇后不同行,不同列,不同左右对角线,输出其对应的所有解。
思路:用回溯的方法先一行一行的放,然后列数从1开始,判断此行当前列是否与前面的列和对角线冲突,如果冲突,立即放弃本次放置,再判断其他的放置方式。如果放置n个后就输出这个方案
输入样例1:
6
输出:
1: (1,2) (2,4) (3,6) (4,1) (5,3) (6,5)
2: (1,3) (2,6) (3,2) (4,5) (5,1) (6,4)
3: (1,4) (2,1) (3,5) (4,2) (5,6) (6,3)
4: (1,5) (2,3) (3,1) (4,6) (5,4) (6,2)
输入样例2:
4
输出:
1: (1,2) (2,4) (3,1) (4,3)
2: (1,3) (2,1) (3,4) (4,2)
代码如下:
// Created by Chenglong Shi on 2021/10/17.
// Only can use to study
// Once found commercial or illegal use will be pursued to the end
// Banning plagiarism
// Email:2230307855@qq.com
// 内部可能含有拼音和汉语注释
// by 史成龙
// 方法:
//
import java.util.Scanner;
public class n_queens {
static int n;
final static int ma=20;
static int index=1;
static int []col=new int[ma];//最大15行15列
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
n=in.nextInt();
pushQueen(1);
in.close();
}
static void pushQueen(int rows){
if(rows>n) show();
for(int j=1;j<=n;j++){
if(isCanPut(rows,j)){
col[rows]=j;
pushQueen(rows+1);
}
}
}
static void show(){
System.out.print(index+": ");
for(int i=1;i<=n;i++)
if(i==1) System.out.print("("+i+","+col[i]+")");
else System.out.print(" ("+i+","+col[i]+")");
System.out.println();
index++;
}
static boolean isCanPut(int i,int j){
if(i==1) return true;
int pre=1;
while(pre<i){
if(col[pre]==j||(Math.abs(i-pre)==Math.abs(j-col[pre])))
return false;
pre++;
}
return true;
}
}
- 约瑟夫问题
一堆人(n个人)坐在一个圆桌上,每次从1开始数,数到m的人自动请出圆桌,然后下一个人借着从1开始数,一直做上述的步骤,现在请你输出,最后剩下的那个人的编号。
思路:利用取模的思想来求出每次需要剔除的人的编号,剔除后,相当于桌子变小,然后进一步取模,直到桌子的大小变为1,然后输出剩下的那个人的编号即可。
输入样例1:
6 2
输出:
5
输入样例2:
12 4
输出:
1
代码如下:
import java.util.ArrayList;
import java.util.Scanner;
public class yue_se_fu {
static int n,m;
static ArrayList<Integer> arr=new ArrayList<Integer>();
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
while(true){
n=in.nextInt();
m=in.nextInt();
if(n==0&&m==0) break;
arr.clear();
for(int i=1;i<=n;i++) arr.add(i);
manageCircle(arr);
}
in.close();
}
static void manageCircle(ArrayList<Integer> arr){
int index=0;
while(arr.size()>0){
if(arr.size()==1){
System.out.println(arr.get(0));
break;
}
index=(index+m-1)% arr.size();
arr.remove(index);
}
}
}
- 排列组合问题
输入m和n,输出排列数和组合数(排列数A(m,n),组合数C(m,n))
思路:根据公式A(m,n)=n!/(n-m)! B(m,n)=A(m,n)/m!,设计出一个求阶乘的函数,然后化简带入到公式即可求出,排列数和组合数。
输入样例1:
4 4
输出:
24 1
输入样例2
3 4
输出:
24 4
代码如下:
import java.util.Scanner;
// Created by Chenglong Shi on 2021/10/19.
// Only can use to study
// Once found commercial or illegal use will be pursued to the end
// Banning plagiarism
// Email:2230307855@qq.com
// 内部可能含有拼音和汉语注释
// by 史成龙
// 方法:
//
public class permutation_and_combination {
static long m,n;
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
m=in.nextLong(); n=in.nextLong();
if(m==0&&n==0) System.out.println("0 0");
else
System.out.println(get_Permutation()+" "+get_combination());
in.close();
}
static long getJieCheng(long be,long en){
if(be==0) return 1;
long num=be;
for(long k=be+1;k<=en;k++) num*=k;
return num;
}
static long get_Permutation(){
long deli=n-m;
if(deli==n) return 1;
else if(deli==0) return getJieCheng(1,n);
else return getJieCheng(n-m+1,n);
}
static long get_combination(){
return get_Permutation()/getJieCheng(1,m);
}
}
- 希望大家多去理解理解西靠思考将其转换为自己得知识,感谢大家一起努力!