1.特性
水平、垂直及斜角元素和都为一个固定值。以三 阶幻方为例:
4 | 9 | 2 |
3 | 5 | 7 |
8 | 1 | 6 |
它的各行元素和,各列元素和,及对角线元素和都是15。
2.代码
import java.util.Arrays;
/**
* @author panda
* @date 2023年8月26日
*
*/
public class MagicSquare {
private int[][] matrix;
private int size;
public MagicSquare(int size) {
this.size = size;
matrix = new int[size][size];
if (size <= 2) {
System.err.println("");
return;
} else if (size % 2 == 1) {
genOdd();
} else {
int ds = size / 2;
if (ds % 2 == 0) {
genDoubleEven();
} else {
genSingleEven();
}
}
}
/**
* 边长为奇数:
*/
public void genOdd() {
int n = 1;
int r = 0;
int c = size / 2;
while (n <= size * size) {
matrix[r][c] = n;
n++;
r--;
c++;
if (r < 0 && c >= size) {
r += 2;
c--;
} else if (r < 0) {
r = size - 1;
} else if (c >= size) {
c = 0;
} else if (matrix[r][c] != 0) {
r += 2;
c--;
}
}
}
/**
* 边长为单偶数:
*/
public void genSingleEven() {
int r = 0;
int c = size / 2 - 1;
int total = size * size / 4;
for (int i = 1; i <= total; i++) {
int type = 1;
if ((r == size / 2 + 1 && c != size / 2 - 1) || (r == size / 2 - 1 && c == size / 2 - 1)) {
type = 0;
}
if (r >= size / 2 + 3) {
type = -1;
}
switch (type) {
case 1:
matrix[r][c] = 4 * i;
matrix[r][c + 1] = 4 * i - 3;
matrix[r + 1][c] = 4 * i - 2;
matrix[r + 1][c + 1] = 4 * i - 1;
break;
case 0:
matrix[r][c] = 4 * i - 3;
matrix[r][c + 1] = 4 * i;
matrix[r + 1][c] = 4 * i - 2;
matrix[r + 1][c + 1] = 4 * i - 1;
break;
default:
matrix[r][c] = 4 * i - 3;
matrix[r][c + 1] = 4 * i;
matrix[r + 1][c] = 4 * i - 1;
matrix[r + 1][c + 1] = 4 * i - 2;
break;
}
int m = (r - 2 + size) % size;
int n = (c + 2) % size;
if (matrix[m][n] > 0) {
r = (r + 2) % size;
} else {
r = m;
c = n;
}
}
}
/**
* 边长为双偶数
*/
public void genDoubleEven() {
int[] arr = new int[size * size / 2];
int index = 0;
for (int r = 0; r < size; r++) {
for (int c = 0; c < size; c++) {
// 符合分割条件
int m = r % 4;
int n = c % 4;
if (m != n && m + n != 3) {
arr[index++] = r * size + c + 1;
matrix[r][c] = 0;
} else {
matrix[r][c] = r * size + c + 1;
}
}
}
Arrays.sort(arr);
int tempIndex = arr.length - 1;
for (int r = 0; r < size; r++) {
for (int c = 0; c < size; c++) {
if (matrix[r][c] == 0) {
matrix[r][c] = arr[tempIndex--];
}
}
}
}
/**
* 幻方检查
* @return true:通过检查;false:没有通过检查
*/
public boolean check() {
//标准和:
int stdSum = size * (size * size + 1) / 2;
//检查行:
int sum = 0;
for (int i = 0; i < size; i++) {
sum = 0;
for (int j = 0; j < size; j++) {
sum += matrix[i][j];
}
if (sum != stdSum) {
return false;
}
}
//检查列:
for (int i = 0; i < size; i++) {
sum = 0;
for (int j = 0; j < size; j++) {
sum += matrix[j][i];
}
if (sum != stdSum) {
return false;
}
}
//检查对角:
sum = 0;
for (int i = 0; i < size; i++) {
sum += matrix[i][i];
}
if (sum != stdSum) {
return false;
}
sum = 0;
for (int i = 0; i < size; i++) {
sum += matrix[i][size - i - 1];
}
if (sum != stdSum) {
return false;
}
return true;
}
public void print() {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
System.out.print(matrix[i][j] + "\t");
}
System.out.println();
}
}
public static void main(String[] args) {
for (int i = 3; i < 256; i++) {
MagicSquare magicSquare = new MagicSquare(i);
//magicSquare.print();
System.out.println("边长为" + i + ":" + magicSquare.check());
}
}
}
3.应用
加密数据。如果有一组数据,可以使用下16阶的幻方进行查表加密:
001 255 254 004 005 251 250 008 009 247 246 012 013 243 242 016
240 018 019 237 236 022 023 233 232 026 027 229 228 030 031 225
224 034 035 221 220 038 039 217 216 042 043 213 212 046 047 209
049 207 206 052 053 203 202 056 057 199 198 060 061 195 194 064
065 191 190 068 069 187 186 072 073 183 182 076 077 179 178 080
176 082 083 173 172 086 087 169 168 090 091 165 164 094 095 161
160 098 099 157 156 102 103 153 152 106 107 149 148 110 111 145
113 143 142 116 117 139 138 120 121 135 134 124 125 131 130 128
129 127 126 132 133 123 122 136 137 119 118 140 141 115 114 144
112 146 147 109 108 150 151 105 104 154 155 101 100 158 159 097
096 162 163 093 092 166 167 089 088 170 171 085 084 174 175 081
177 079 078 180 181 075 074 184 185 071 070 188 189 067 066 192
193 063 062 196 197 059 058 200 201 055 054 204 205 051 050 208
048 210 211 045 044 214 215 041 040 218 219 037 036 222 223 033
032 226 227 029 028 230 231 025 024 234 235 021 020 238 239 017
241 015 014 244 245 011 010 248 249 007 006 252 253 003 002 256
当然在应用时,可以将所有值减1,或者将256替换成0,再做转换。