昨天同事发了个图片过来,要求输出N阶魔方的,横竖跟对角线的和都相等!
所以就研究了一下,感觉里面的算法比较容易把人搞晕,C#代码如下:
using System;
namespace MagiCube
{
class Program
{
static void Main(string[] args)
{
int n = 0;
bool parseOK = false;
bool exit = false;
do
{
do
{
try
{
Console.Clear();
Console.WriteLine("请输入魔方的阶数:");
n = Int32.Parse(Console.ReadLine());
if (n < 3 || n > 99)
{
Console.WriteLine("输入的数字不能小于3或大于99,请重试!");
Console.ReadKey();
parseOK = false;
continue;
}
parseOK = true;
}
catch (FormatException)
{
Console.WriteLine("输入的不是整数,请重试!");
parseOK = false;
Console.ReadKey();
}
} while (!parseOK);
GetData(n, true);
Console.WriteLine("是否继续运行?(按“Y”继续,否则退出!)");
exit = (Console.ReadKey().Key.ToString().ToLower() == "y" ? false : true);
} while (!exit);
}
public static void GetData(int n,bool checkSum) //根据n的值决定调用的函数,并输出结果
{
int[,] N = new int[n, n];
if (n % 2 != 0) //n为基数时
{
N = Odd(n);
}
else if (n % 4 == 0) //n为4的倍数时
{
N = Even(n);
}
else if (n % 4 == 2) //n为非4的倍数的其他偶数时(n%4==2)
{
N = Even2(n);
}
//else
//{
// Console.WriteLine("无法处理数字 {0} !", n);
//}
Console.WriteLine(new string('=', 50));
Print(N);
if (checkSum)
{
Console.WriteLine(new string('=', 50));
CheckSum(N);
}
Console.WriteLine(new string('=', 50));
}
public static void CheckSum(int[,] N) //输出N阶魔方每行每列及对角线的和
{
int row = N.GetLength(0);
int col = N.GetLength(1);
int sumrow = 0;
int sumcol = 0;
int sumdia = 0;
for (int x = 0; x < row; x++)
{
for (int y = 0; y < col; y++)
{
sumrow += N[x, y];
sumcol += N[y, x];
}
Console.WriteLine("行{0}:{1},列{0}:{1}", x + 1, sumrow, x + 1, sumcol);
sumrow = 0;
sumcol = 0;
}
for (int m = 0; m < row; m++)
{
sumdia += N[m, m];
}
Console.Write("对角线1:{0},", sumdia);
sumdia = 0;
int i = 0;
for (int j = (col - 1); j >= 0; j--)
{
sumdia += N[i, j];
}
Console.WriteLine("对角线2:{0}", sumdia);
}
public static int[,] Odd(int n) //n为基数时
{
int[,] N = new int[n, n];
int x = 0;
int y = (n - 1) / 2;
for (int i = 1; i <= n * n; i++)
{
x = (x < 0 ? (n + x) : (x > (n - 1) ? (x - n) : x));
y = (y > (n - 1) ? (y - n) : (y < 0 ? (n + y) : y));
if (N[x, y] == 0)
{
if ((i % n) == 0 && i != 1)
{
N[x++, y] = i;
}
else
{
N[x--, y++] = i;
}
}
}
return N;
}
public static int[,] Even(int n) //n为4的倍数时
{
int[,] N = new int[n, n];
/*消去对角线法
* 适用:四之倍数阶魔方阵
* 方法:(1)先将整个方阵划分成k*k个4阶方阵,然后在每个4阶方阵的对角线上做记号
* (2)由左而右、由上而下,遇到没有记号的位置才填数字,但不管是否填入数字,每移动一格数字都要加1
* (3)自右下角开始,由右而左、由下而上,遇到没有数字的位置就填入数字,但每移动一格数字都要加1
* 参考:http://blog.dns0351.com/article/DailyBlog/479.htm
*/
for (int x = 0; x < n; x += 4)
{
for (int y = 0; y < n; y += 4)
{
N[x, y] = 1;
N[x + 3, y + 3] = 1;
N[x + 1, y + 1] = 1;
N[x + 2, y + 2] = 1;
N[x, y + 3] = 1;
N[x + 3, y] = 1;
N[x + 1, y + 2] = 1;
N[x + 2, y + 1] = 1;
}
}
int m = n * n;
for (int i = 1; i <= n * n; i++)
{
if (N[(i - 1) / n, (i - 1) % n] != 1)
{
N[(i - 1) / n, (i - 1) % n] = i;
}
else
{
N[(i - 1) / n, (i - 1) % n] = m;
}
m--;
}
return N;
}
public static int[,] Even2(int n) //n为非4的倍数的其他偶数时(n%4==2)
{
/* n为非4的倍数的其他偶数时,划分成四个奇数方阵示意图
* |
* B区(次小) | C区(次大)
* ---------------------------
* D区(最大) | A区(最小)
* |
*/
int[,] N = new int[n, n];
int[,] initN = Odd(n / 2);
int v = n * n / 4;
for (int x = 0; x < n / 2; x++)
{
for (int y = 0; y < n / 2; y++)
{
N[x + n / 2, y + n / 2] = initN[x, y]; //A区
N[x, y] = initN[x, y] + v; //B区
N[x, y + n / 2] = initN[x, y] + 2 * v; //C区
N[x + n / 2, y] = initN[x, y] + 3 * v; //D区
}
}
int tmp;
int m = (n - 2) / 4;
if (m > 1)
{
for (int i = 0; i <= m - 2; i++)
{
for (int j = 0; j < n / 2; j++)
{
tmp = N[i, j];
N[i, j] = N[i, n / 2 + j];
N[i, n / 2 + j] = tmp;
}
}
}
for (int i = n - m; i < n; i++)
{
for (int j = 0; j < n / 2; j++)
{
tmp = N[i, j];
N[i, j] = N[i, n / 2 + j];
N[i, n / 2 + j] = tmp;
}
}
tmp = N[n / 2 + m, m];
N[n / 2 + m, m] = N[n / 2 + m, n / 2 + m];
N[n / 2 + m, n / 2 + m] = tmp;
tmp = N[n - 1, m];
N[n - 1, m] = N[n - 1, n / 2 + m];
N[n - 1, n / 2 + m] = tmp;
return N;
}
public static void Print(int[,] N)
{
int maxLength = 4;
int preLen = 0;
for (int i = 0; i < N.GetLength(0); i++)
{
for (int j = 0; j < N.GetLength(1); j++)
{
Console.Write(new String(' ', maxLength - preLen));
Console.Write(N[i, j]);
preLen = N[i, j].ToString().Length;
}
for (int k = 0; k < maxLength - 2; k++)
{
Console.WriteLine("");
}
preLen = 0;
}
}
}
}