洛谷P1406 Java解法

题目出处
在这里插入图片描述
思路:dfs+剪枝。
dfs:从头到尾把每种组合都搜一遍,如果遇到满足条件就疯狂return,但最后一个点TLE
剪枝:稍加思索就发现,每一行之和必须是所有数之和除以n,只要不满足这 个条件就return,这样就不会TLE了

代码简单易懂(最好不要在dfs里写上面的那个剪枝的判断,这样的话java很容易MLE):

package search;

import java.util.Arrays;
import java.util.Scanner;

public class P1406 {
	static int n, arr[], res, temp[], tot;
	static boolean vis[], flag;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		arr = new int[n * n + 1];
		temp = new int[n * n + 1];
		vis = new boolean[n * n + 1];
		for (int i = 1; i <= n * n; i++) {
			arr[i] = sc.nextInt();
		}
		for (int i = 1; i <= n * n; i++) {
			tot = tot + arr[i];
		}
		Arrays.sort(arr, 1, n * n + 1);// 因为按照最小字典序,因此必须升序排列
		dfs(1);

	}

	public static void dfs(int num) {
		if (num > n * n && check(temp) && !flag) {
			flag = true;
			for (int i = 1; i <= n; i++) {
				res = res + temp[i];
			}
			System.out.println(res);
			for (int i = 1; i <= n; i++) {
				for (int j = n * (i - 1) + 1; j <= n * i; j++) {
					System.out.print(temp[j] + " ");
				}
				System.out.println();
			}
			return;
		}
		
		//比较重要的剪枝,没的话会TLE
		if ((num - 1) % n == 0 && num >= n + 1) {// 只有当temp里的个数大于n+1且个数是n的倍数才进行判断这一行的和是不是tot/n
			if (!sum(temp, (num - 1) / n)) {//判断第n行的和是不是tot/n
				return;
			}
		}
		if (flag) {
			return;
		}
		if (num > n * n) {
			return;
		}
		for (int i = 1; i <= n * n; i++) {
			if (!vis[i]) {// 如果第i个数没被用过
				vis[i] = true;
				temp[num] = arr[i];
				dfs(num + 1);
				if (flag) {
					break;
				}
				vis[i] = false;
			}
		}
	}
	/**
	 * 功能:判断第a行的和是不是tot/n,很容易证明幻方的每一行就是所有数的和除以n
	 * @param sz
	 * @param a
	 * @return
	 */
	public static boolean sum(int[] sz, int a) {
		int s = 0;
		for (int i = (a - 1) * n + 1; i <= a * n; i++) {
			s += sz[i];
		}
		if (s == tot / n) {
			return true;
		}
		return false;
	}
	/**
	 * 功能:判断是不是幻方(因为懒,所以直接手写了,也可以写一个适用于所有n的check函数)
	 * @param sz
	 * @return
	 */
	public static boolean check(int sz[]) {
		if (n == 1) {
			return true;
		}
		if (n == 2) {
			int r[] = new int[7];
			r[1] = sz[1] + sz[2];
			r[2] = sz[3] + sz[4];
			r[3] = sz[1] + sz[3];
			r[4] = sz[2] + sz[4];
			r[5] = sz[1] + sz[4];
			r[6] = sz[2] + sz[3];
			for (int i = 1; i <= 5; i++) {
				if (r[i] != r[i + 1]) {
					return false;
				}
			}
		}
		if (n == 3) {
			int r[] = new int[9];
			r[1] = sz[1] + sz[2] + sz[3];
			r[2] = sz[4] + sz[5] + sz[6];
			r[3] = sz[7] + sz[8] + sz[9];// 行
			r[4] = sz[1] + sz[4] + sz[7];
			r[5] = sz[2] + sz[5] + sz[8];
			r[6] = sz[3] + sz[6] + sz[9];// 列
			r[7] = sz[3] + sz[5] + sz[7];
			r[8] = sz[1] + sz[5] + sz[9];// 对角线
			for (int i = 1; i <= 7; i++) {
				if (r[i] != r[i + 1]) {
					return false;
				}
			}
		}
		if (n == 4) {
			int r[] = new int[11];
			r[1] = sz[1] + sz[2] + sz[3] + sz[4];
			r[2] = sz[5] + sz[6] + sz[7] + sz[8];
			r[3] = sz[9] + sz[10] + sz[11] + sz[12];
			r[4] = sz[13] + sz[14] + sz[15] + sz[16];
			r[5] = sz[1] + sz[5] + sz[9] + sz[13];
			r[6] = sz[2] + sz[6] + sz[10] + sz[14];
			r[7] = sz[3] + sz[7] + sz[11] + sz[15];
			r[8] = sz[4] + sz[8] + sz[12] + sz[16];
			r[9] = sz[1] + sz[6] + sz[11] + sz[16];
			r[10] = sz[4] + sz[7] + sz[10] + sz[13];
			for (int i = 1; i <= 9; i++) {
				if (r[i] != r[i + 1]) {
					return false;
				}
			}
		}
		return true;
	}
}

猜你喜欢

转载自blog.csdn.net/TXXERIN/article/details/107743912