[算法]暴力求解法:回溯法


在递归构造中,生成和检查过程可以有机结合起来,从而减少不必要的枚举,这就是回溯法。当把问题分成若干步骤并递归求解时,如果当前步骤没有合法选择,则函数将返回上一级递归调用,这种现象称为回溯。正是因为这个原因,递归枚举算法常被称为回溯法,应用十分普遍。

八皇后问题

问题:在棋盘上放置8个皇后,使得它们互不攻击,此时每个皇后的攻击范围为同行同列和同
对角线,要求找出所有解
分析:

  1. 四皇后问题的解答树
    四皇后问题的解答树
  2. 既然是逐行放置的,则皇后肯定不会横向攻击,因此只需检查是否纵向和斜向攻击即可。条件“cur-C[cur] == j-C[j] || cur+C[cur] == j+C[j]”用来判断皇后(cur,C[cur])和(j,C[j])是否在同一条对角线上。
    在这里插入图片描述代码:
import java.util.Scanner;

public class Main {
	static int n;
	static int tot=0;
	static int[] A=new int[10000];
	public static void main(String[] args) {
		Scanner s=new Scanner(System.in);
		n= s.nextInt();
		search(0);
		System.out.println(tot);
	}

	private static void search(int cur) {
		if(cur == n) tot++;//当cur等于行数,那么就代表摆放成功
		else for(int i=0;i<n;i++)
		{
			int ok = 1;
			A[cur] = i;//尝试把第cur行的皇后放入第i列	
			for(int j=0;j<cur;j++)
			{
				if(A[cur]==A[j]||cur-A[cur]==j-A[j]||cur+A[cur]==j+A[j])//判断是否同列同主对角线和同副对角线 
				{
					ok = 0;	break;//如果是,则不递归并退循环,回溯 
				}
			}
			if(ok>0) search(cur+1);//如果合法,则递归 
		}
	}
}

改进:利用二维数组vis[2][ ]直接判断当前尝试的皇后所在的列和两个对角线是否已有其他皇后。注意到主对角线标识y-x可
能为负,存取时要加上n。

import java.util.Scanner;

public class Main {
	static int n;
	static int tot=0;
	static int[] C=new int[10000];  //用来存储解
	static int[][] vis=new int[10000][10000];
	public static void main(String[] args) {
		Scanner s=new Scanner(System.in);
		n= s.nextInt();
		search(0);
		System.out.println(tot);
	}

	private static void search(int cur) {
		if(cur == n) 
			{
			for(int i=0;i<n;i++)
				System.out.print(C[i]);
			System.out.println();
			tot++;//当cur等于行数,那么就代表摆放成功
			}
		else for(int i=0;i<n;i++)
		{
			if(vis[0][i]==0 && vis[1][cur+i]==0 && vis[2][cur-i+n]==0) {
				//利用二维数组直接判断
				C[cur] = i; //如果不用打印解,整个C数组都可以省略
				vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 1; //修改全局变量
				search(cur+1);
				vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 0; //切记!一定要改回来
				}
		}
	}
}


素数环(Prime Ring Problem)

输输入正整数n,把整数1, 2, 3,…, n组成一个环,使得相邻两个整数之和均为素数。输出
时从整数1开始逆时针排列。同一个环应恰好输出一次。n≤16。
样例输入:
6
样例输出:
1 4 3 2 5 6
1 6 5 2 3 4

代码:

import java.util.Scanner;

public class Main {
	static int n;
	static int[] A=new int[1000];
	static int[] vis=new int[1000];
	static int[] isp=new int[1000];

	public static void main(String[] args) {
		Scanner s=new Scanner(System.in);
		n= s.nextInt();
		for(int i = 2; i <= n*2; i++) 
			isp[i] = is_prime(i);
		A[0] = 1;
        dfs(1);
	}
	
	private static int is_prime(int n)
	{
	    if(n<=1) return 0;
	    int k = (int) Math.floor(Math.sqrt(n)+0.5);
	    for(int i=2;i<=k;i++)
	        if(n%i==0)
	            return 0;
	    return 1;
	}


	private static void dfs(int cur)
	{

	    if(cur==n&&isp[A[0]+A[n-1]]!=0)
	    {
	        for(int i=0;i<n;i++)
	        	System.out.print(A[i]+" ");
	        System.out.println();
	    }
	    else for(int i=2;i<=n;i++)
	    {
	        if(vis[i]==0&&isp[i+A[cur-1]]!=0)
	        {   
	            A[cur]=i;
	            vis[i]=1;
	            dfs(cur+1);
	            vis[i]=0;
	        }
	    }
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41655934/article/details/89216679
今日推荐