首页 > 其他分享 >【蓝桥杯基础题】2017年省赛—九宫幻方

【蓝桥杯基础题】2017年省赛—九宫幻方

时间:2023-02-09 23:02:25浏览次数:77  
标签:排列 int 幻方 蓝桥 ++ permutation 2017 include 省赛


一、题目背景

本题为2020年省赛程序设计题

  • C/C++ C 组第8题

二、题目描述

1.问题描述

小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将1~9不重复的填入一个3 x 3的矩阵当中,使得每一行、每一列和每一条对角线的和都是相同的。 三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:“二四为肩,六八为足,左三右七,戴九履一,五居其中”,通过这样的一句口诀就能够非常完美的构造出一个九宫格来。

4 9 2
3 5 7
8 1 6

有意思的是,所有的三阶幻方,都可以通过这样一个九宫格进行若干镜像和旋转操作之后得到。现在小明准备将一个三阶幻方(不一定是上图中的那个)中的一些数抹掉,交给邻居家的小朋友来进行还原,并且希望她能够判断出究竟是不是只有一个解。而你,也被小明交付了同样的任务,但是不同的是,你需要写一个程序。

2.输入格式  

输入仅包含单组测试数据。 每组测试数据为一个3 x 3的矩阵,其中为0的部分表示被小明抹去的部分。 对于100%的数据,满足给出的矩阵至少能还原出一组可行的三阶幻方。

3.输出格式  

如果仅能还原出一组可行的三阶幻方,则将其输出,否则输出“Too Many”(不包含引号)。

4.一个例子

下面是一个样例 输入:

0 7 2
0 5 0
0 3 0

输出:

6 7 2
1 5 9
8 3 4

三、题目分析

1. 执果索因

通过使用科技的力量或者自己独立思考,提前找出三阶幻方的所有可能解。 再将自己已经知道的所有解提前放入程序里面,与输入的数进行比对。 如果只能比对出一组可行的幻方,则将其输出。 科技力量直通车→科技创造美好生活 在这里插入图片描述

2. 全排列

上面的方法是将已知答案放入程序中,但是更多的情况,我们是不知道答案的。

对此,我们只能将所有可能都弄出来。

这里就需要利用数学中的排列知识了。

排列,一般地,从n个不同元素中取出m(m≤n)个元素,按照一定的顺序排成一列,叫做从n个元素中取出m个元素的一个排列(permutation)。特别地,当m=n时,这个排列被称作全排列(all permutation)。

C++algorithm中提供了内置的全排列函数next_permutation

下面介绍一下next_permutation函数

在这里插入图片描述

使用方法:next_permutation(数组头地址,数组尾地址);

若下一个排列存在,则返回真,如果不存在则返回假

举个例子:

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
	int b[3] = { 1,2,3 };
	do
	{
		for (int i = 0; i < 3; ++i)
			cout << b[i] ;
		cout << endl;
	} while (next_permutation(b, b + 3));
	return 0;
}

在这里插入图片描述

利用循环,和next_permutation的返回值,巧妙的得到全排列结果。 然后利用九宫幻方的性质,检查是不是九宫幻方。

九宫幻方:每一行、每一列、每一对角线的和都相同。

3. 深度优先搜索(DFS)

在这里插入图片描述

四、代码汇总

1. 执果索因

#include <iostream>
#include<string>
#include <algorithm>
using namespace std;
int main()
{
	int a[3][3], f = 0, k = 0, i, j;
	//初始化
	string b = "000000000";
	//所有可能的答案
	string vis[8] = { "816357492","618753294","492357816","294753618","672159834","834159672","276951438","438951276" };
	int v[8] = { 0 };
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cin >> a[i][j];
			//将int转为string
			b[k++] = a[i][j] + '0';
		}
	}
	for (i = 0; i < 8; i++)
	{
		for (j = 0; j < 9; j++)
		{
			if (b[j] != '0')
			{
				//比较下一个字符串
				if (vis[i][j] != b[j])
					break;
			}
		}
		if (j == 9)
		{
			f++;
			v[i] = 1;
		}
		if (f > 1)
		{
			cout << "Too Many" << endl;
			break;
		}
	}
	k = 0;
	if (f == 1)
	{
		for (i = 0; i < 9; i++)
			if (v[i] == 1)break;
		while (k < 9)
		{
			cout << vis[i][k++] << " ";
			if (k % 3 == 0)cout << endl;
		}
	}
	return 0;
}

2. 全排列

#include <iostream>
#include<string>
#include <algorithm>
using namespace std;
int arr[9];
int str[9] = { 1,2,3,4,5,6,7,8,9 };

bool flag = true;
int ans = 0;
//检查是不是九宫幻方
bool check(int a[])
{
	int a1 = a[0] + a[1] + a[2];
	int a2 = a[3] + a[4] + a[5];
	int a3 = a[6] + a[7] + a[8];
	int a4 = a[0] + a[3] + a[6];
	int a5 = a[1] + a[4] + a[7];
	int a6 = a[2] + a[5] + a[8];
	int a7 = a[2] + a[4] + a[6];
	int a8 = a[0] + a[4] + a[8];
	if (a1 == a2 && a2 == a3 && a3 == a4 && a4 == a5 && a5 == a6 && a6 == a7 && a7 == a8)
		return true;
	return false;
}

int main() 
{
	for (int i = 0; i < 9; i++)
		cin >> arr[i];
	do {
		if (check(str))
		{
			flag = true;
			for (int i = 0; i < 9; i++)
			{
				if (arr[i] != 0 && arr[i] != str[i])
				{
					flag = false;
				}
			}

			if (flag)
			{
				for (int i = 0; i < 9; i++)
					arr[i] = str[i];
				ans++;
			}
		}
	} while (next_permutation(str, str + 9));

	if (ans == 1)
	{
		int k = 0;
		for (int i = 0; i < 3; i++)
		{
			for (int j = 0; j < 3; j++)
			{
				cout << arr[k] << " ";
				k++;
			}
			cout << endl;
		}
	}
	else if (ans > 1)
		cout << "Too Many" << endl;
	return 0;
}

3. DFS

#include <iostream>
#include<string>
#include <algorithm>
int a[5][5];
int b[5][5];
int vis[15];
int ans = 0;
using namespace std;
bool check()
{
	int sum1, sum2;
	int x = a[1][1] + a[1][2] + a[1][3];
	for (int i = 1; i <= 3; i++)
	{
		sum1 = 0, sum2 = 0;
		for (int j = 1; j <= 3; j++)
		{
			sum1 += a[i][j];
			sum2 += a[j][i];
		}
		if (sum1 != x || sum2 != x)
			return 0;
	}
	sum1 = a[1][1] + a[2][2] + a[3][3];
	sum2 = a[1][3] + a[2][2] + a[3][1];
	if (sum1 != x || sum2 != x)
		return false;
	return true;
}
void dfs(int num)
{
	if (num == 9)
	{
		if (check())
		{
			for (int i = 1; i <= 3; i++)
				for (int j = 1; j <= 3; j++)
					b[i][j] = a[i][j];
			ans++;
		}
		return;         
	}
	for (int i = 1; i <= 3; i++)
		for (int j = 1; j <= 3; j++)
		{
			if (a[i][j] == 0)
			{
				for (int k = 1; k <= 9; k++)
				{
					if (!vis[k])
					{
						vis[k] = 1;
						a[i][j] = k;
						dfs(num + 1);
						vis[k] = 0;
						a[i][j] = 0;
					}
				}
				return;
			}
		}
}
int main()
{
	int num = 0;
	for (int i = 1; i <= 3; i++)
		for (int j = 1; j <= 3; j++)
		{
			cin >> a[i][j];
			vis[a[i][j]] = 1;
			if (a[i][j] != 0)
				num++;
		}
	dfs(num);
	if (ans == 1)
		for (int i = 1; i <= 3; i++)
		{
			for (int j = 1; j <= 3; j++)
				cout << b[i][j] << " ";
			cout << endl;
		}
	else
		cout << "Too Many" << endl;
	return 0;
}

五、总结

1. 全排列

排列、全排列的计算。

全排列函数:next_permutation 的用法。

2. 九宫幻方的判断

九宫幻方:每一行、每一列、每一对角线的和都相同。

标签:排列,int,幻方,蓝桥,++,permutation,2017,include,省赛
From: https://blog.51cto.com/zxhy/6047360

相关文章