首页 > 编程语言 >九宫幻方(DFS实现)c++

九宫幻方(DFS实现)c++

时间:2024-03-22 12:29:05浏览次数:34  
标签:cnt int sum DFS check c++ 对角线 幻方

题目描述

题目分析

要完成这个问题,我们需要做这几步

1.用1~9的数字替换掉输入中的0,且幻方中不能出现重复元素

2.替换完成后,要判断是否为幻方

判断是否为幻方

bool check()//检查是否为幻方 
{
	int sum=a[1][1]+a[2][2]+a[3][3];//左对角线的和 
	if(sum!=a[1][3]+a[2][2]+a[3][1])	return false;//判断右对角线的和 
	for(int i=1;i<=3;i++)
	{
		int tmp1=0,tmp2=0;
		for(int j=1;j<=3;j++)	
		{
			tmp1+=a[i][j];//计算一行的和 
			tmp2+=a[j][i];//计算一列的和 
		}
		if(tmp1!=sum||tmp2!=sum)	return false;
	}
	return true;
}

用dfs方法替换0元素

void dfs(int now)
{
	if(now>n)
	{
		if(check())
		{
			cnt++;//如果是幻方,数量+1 
			for(int i=1;i<=3;i++)//将该矩阵复制到ans矩阵中 
				for(int j=1;j<=3;j++)
					ans[i][j]=a[i][j];
		}
		return;
	}
	int x=p[now].first,y=p[now].second;//根据当前的now索引,从p数组中获取对应的坐标(x, y),这是下一个要填入的数字的位置
	for(int k=1;k<=9;k++)
	{
		if(vis[k])	continue;//如果数字k已经被使用过(即vis[k]为1),则跳过该次循环 
		a[x][y]=k;//在位置(x, y)填入数字k
		vis[k]=1;//标记k,说明其已经使用过 
		dfs(now+1);//递归调用dfs 
		a[x][y]=0;//回溯,将位置(x, y)的数字重新设置为0
		vis[k]=0;//回溯,标记数字k为未使用
	}
}

完整代码

#include<bits/stdc++.h>
using namespace std;
int vis[10],a[5][5],ans[5][5];
int n,cnt;
pair<int,int>p[10];
bool check()//检查是否为幻方 
{
	int sum=a[1][1]+a[2][2]+a[3][3];//左对角线的和 
	if(sum!=a[1][3]+a[2][2]+a[3][1])	return false;//判断右对角线的和 
	for(int i=1;i<=3;i++)
	{
		int tmp1=0,tmp2=0;
		for(int j=1;j<=3;j++)	
		{
			tmp1+=a[i][j];//计算一行的和 
			tmp2+=a[j][i];//计算一列的和 
		}
		if(tmp1!=sum||tmp2!=sum)	return false;
	}
	return true;
}

void dfs(int now)
{
	if(now>n)
	{
		if(check())
		{
			cnt++;//如果是幻方,数量+1 
			for(int i=1;i<=3;i++)//将该矩阵复制到ans矩阵中 
				for(int j=1;j<=3;j++)
					ans[i][j]=a[i][j];
		}
		return;
	}
	int x=p[now].first,y=p[now].second;//根据当前的now索引,从p数组中获取对应的坐标(x, y),这是下一个要填入的数字的位置
	for(int k=1;k<=9;k++)
	{
		if(vis[k])	continue;//如果数字k已经被使用过(即vis[k]为1),则跳过该次循环 
		a[x][y]=k;//在位置(x, y)填入数字k
		vis[k]=1;//标记k,说明其已经使用过 
		dfs(now+1);//递归调用dfs 
		a[x][y]=0;//回溯,将位置(x, y)的数字重新设置为0
		vis[k]=0;//回溯,标记数字k为未使用
	}
}

signed main()
{
	for(int i=1;i<=3;i++)
	{
		for(int j=1;j<=3;j++)
		{
			cin>>a[i][j];
			if(a[i][j]==0)	p[++n]=make_pair(i,j);//如果某坐标上的元素为0,就用p数组记录它的坐标
			vis[a[i][j]]=1; //对矩阵中出现过的数打上标记,0也打上标记了,但无所谓,因为幻方要填的数字没有0 
		}
	}
	dfs(1);//开始搜索
	if(cnt==1)//如果幻方的个数为1,直接输出ans矩阵 
	{
		for(int i=1;i<=3;i++)
		{
			for(int j=1;j<=3;j++)
			{
				if(j<=2)	cout<<ans[i][j]<<" "; 	
				else	cout<<ans[i][j]<<endl;
				
			}
			
		} 	
	}
	else	cout<<"Too Many"<<endl;
	return 0;	
}

标签:cnt,int,sum,DFS,check,c++,对角线,幻方
From: https://blog.csdn.net/weixin_74329365/article/details/136937119

相关文章

  • DFS基础——迷宫
    迷宫关于dfs和bfs的区别讲解。对于上图,假设我们要找从1到5的最短路,那么我们用dfs去找,并且按照编号从大到小的顺序去找,首先找到的路径如下,从节点1出发,我们发现节点2可以走,于是我们就走向了节点2,然后又发现节点2可以走向节点4,于是走向了节点4,然后从节点4走向了节点5,......
  • DFS进阶——全排列
    通过后续的题目希望大家明白,dfs不仅仅是对图的遍历,他还有很多用法。DFS进阶1——回溯先说一下回溯的板子dfs(){for(......){标记信息dfs()撤销标记}}回溯模板——递归实现排列型枚举题目分析其实就是对1~n的数字全排列,这里就可以用dfs去做,1~n全排......
  • SQLiteC/C++接口详细介绍sqlite3_stmt类(一)
    返回目录:SQLite—免费开源数据库系列文章目录   上一篇:SQLiteC/C++接口详细介绍sqlite3_stmt类简介下一篇:SQLiteC/C++接口详细介绍sqlite3_stmt类(二)​序言:本文开始了SQLite的第二个类的详细介绍了,有兴趣的朋友可以关注更新一下。 1、sqlite3_prepare_v2()`sqlite3......
  • HDFSRPC安全认证Token篇推广
    本文主要阐述HDFSRPC安全认证相关的实现。主要介绍Token相关的实现。写在前面相关bloghttps://blog.csdn.net/hncscwc/article/details/124722784https://blog.csdn.net/hncscwc/article/details/124958357Token由来在探究完Kerberos,我一直在想一个问题,rpcConnection已经完......
  • C++对象切片探秘:派生类对象如何被‘切割’?
     概述:C++中的对象切片指通过将派生类对象赋值给基类对象,导致派生部分被“切掉”,只保留基类部分。这可能发生在值传递、赋值等操作中。对象切片的基础功能示例展示了派生类对象赋值给基类对象时的现象,而高级功能示例则展示了通过基类指针实现派生类对象的访问和多态。对象切片......
  • C++序列点解析:确保代码行为可控的关键步骤
     概述:在C++中,序列点是表达式中确保求值顺序的点。其缺失可能导致未定义行为。基础功能示例演示了自增运算符的序列点,而高级功能示例展示了函数调用的序列点,有助于避免不确定行为。在编写代码时遵循序列点规则是确保程序行为可预测的关键。在C++中,序列点是在表达式中保证求值......
  • C++11自定义字面量操作符
    自定义字面量操作符是从C++11标准开始引入的。它允许程序员为特定类型定义自定义的字面量表示法,以提供更加直观和灵活的语法。通过定义自定义字面量操作符,可以让程序更容易阅读和理解,同时提高代码的可读性和表达能力。根据C++标准(C++Standard),对自定义字面量操作符有如下定义:自......
  • C++开发基础——可变参数与可变参数模板
    一,可变参数1.基础概念可变参数在C语言和C++语言编程中都有应用。可变参数的含义是:在函数传参的时候,参数的数量、类型都是可变的,不确定的。在C语言中,应用到可变参数的是可变参数函数和可变参数的宏。在C++语言中,C++11标准提供了两种使用可变参数的方式:1.如果可变参数的参......
  • C++开发基础——智能指针
    一,智能指针1.智能指针简介智能指针是用法和行为类似于指针的类对象。智能指针的底层对原始指针做了一定的封装。智能指针除了像指针一样可以存储变量的地址,还提供了其他功能,比如可以管理动态内存分配,对引用进行计数等。当智能指针所指向的变量离开了作用域或被重置时,智能......
  • AcWing 1230. K倍区间 C++满分题解
    原题链接https://www.acwing.com/problem/content/1232/题目分析求区间和,我们可以通过前缀和来求出。我们规定sum[i]表示第1个元素到第i个元素的和。那么sum[r]-sum[l-1]就是区间[l,r]的和。一维前缀和for(inti=1;i<=n;i++){scanf("%lld",&sum[i]);......