【回溯】B027_LQ_六角幻方 四阶幻方 九宫幻方 反幻方 魔方状态 纸牌三角形(恶心的剪枝)

本文主要是介绍【回溯】B027_LQ_六角幻方 四阶幻方 九宫幻方 反幻方 魔方状态 纸牌三角形(恶心的剪枝),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、六角幻方

把 1、2、3 … 19 共 19 个整数排列成六角形状,如下:
在这里插入图片描述
要求每个直线上的数字之和必须相等,共有 15 条 直线哦!

再给点线索吧!我们预先填好了 2 个数字,第一行的头两个数字是:15、13,如图。
在这里插入图片描述
请你填写出黄色一行的 5 个数字。数字间用空格分开

方法一:深搜+剪枝

思路

真的恶心,

#include<bits/stdc++.h>
using namespace std;
int a[20]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
int A[19], vis[19];
void dfs(int i) {if (i==7 && 28+A[2] != A[3]+A[4]+A[5]+A[6]) return;if (i==8 && 28+A[2] != A[0]+A[3]+A[7]) return;if (i==12 && (28+A[2] != A[7]+A[8]+A[9]+A[10]+A[11] || 28+A[2] != A[2]+A[6]+A[11])) return;if (i==13 && 28+A[2] != A[1]+A[4]+A[8]+A[12]) return;if (i==16 && (28+A[2] != A[12]+A[13]+A[14]+A[15] || 28+A[2] != A[5]+A[10]+A[15])) return;if (i==17 && (28+A[2] != A[2]+A[5]+A[9]+A[13]+A[16] || 28+A[2]!=A[7]+A[12]+A[16])) return;if (i==18 && (28+A[2] != A[6]+A[10]+A[14]+A[17] || 28+A[2] != A[3]+A[8]+A[13]+A[17])) return;if (i==19 && 28+A[2] == A[16]+A[17]+A[18]) {for (int k=7; k<=11; k++) printf("%d ", A[k]);return;}for (int j=1; j<20; j++) {if (vis[j]) continue;vis[j]=1;A[i]=a[j-1];dfs(i+1);vis[j]=0;}
}
int main() {memset(vis, 0, sizeof vis);A[0]=15, A[1]=13; vis[13]=vis[15]=1;dfs(2);return 0;
}
二、四阶幻方

把1~16的数字填入4x4的方格中,使得行、列以及两个对角线的和都相等,满足这样的特征时称为:四阶幻方。

四阶幻方可能有很多方案。如果固定左上角为1,请计算一共有多少种方案。

比如:
1 2 15 16
12 14 3 5
13 7 10 4
8 11 6 9以及:
1 12 13 8
2 14 7 11
15 3 10 6
16 5 4 9
就可以算为两种不同的方案

代码类似,需要恶心的剪枝…

#include<bits/stdc++.h>
using namespace std;
int ans, A[17], vis[17];void dfs(int i) {if (i==8 && A[0]+A[1]+A[2]+A[3] != A[4]+A[5]+A[6]+A[7]) return;if (i==12 && A[4]+A[5]+A[6]+A[7] != A[8]+A[9]+A[10]+A[11]) return;if (i==13 && (A[8]+A[9]+A[10]+A[11] != A[0]+A[4]+A[8]+A[12] || A[8]+A[9]+A[10]+A[11] != A[3]+A[6]+A[9]+A[12])) return;if (i==14 && A[8]+A[9]+A[10]+A[11] != A[1]+A[5]+A[9]+A[13]) return;if (i==15 && A[8]+A[9]+A[10]+A[11] != A[2]+A[6]+A[10]+A[14]) return;if (i==16) {int s1=A[8]+A[9]+A[10]+A[11], s2=A[12]+A[13]+A[14]+A[15], s3=A[3]+A[7]+A[11]+A[15], s4=A[0]+A[5]+A[10]+A[15];if (s1!=s2 || s1!=s3 || s1!=s4) return;ans++;}for (int next=1; next<17; next++) if (!vis[next]) {vis[next]=1, A[i]=next;dfs(i+1);vis[next]=0;}
}
int main() {std::ios::sync_with_stdio(false);vis[1]=1;A[0]=1;dfs(1);cout << ans;return 0;
}

在这里插入图片描述

三、九宫幻方

小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将1~9不重复的填入一个3*3的矩阵当中,使得每一行、每一列和每一条对角线的和都是相同的。

三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:“二四为肩,六八为足,左三右七,戴九履一,五居其中”,通过这样的一句口诀就能够非常完美的构造出一个九宫格来。

4 9 2
3 5 7
8 1 6

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

而你呢,也被小明交付了同样的任务,但是不同的是,你需要写一个程序~

输入
输入仅包含单组测试数据。
每组测试数据为一个3*3的矩阵,其中为0的部分表示被小明抹去的部分。
对于100%的数据,满足给出的矩阵至少能还原出一组可行的三阶幻方。
输出
如果仅能还原出一组可行的三阶幻方,则将其输出,否则输出“Too Many”(不包含引号)

样例输入
0 7 2
0 5 0
0 3 0
样例输出
6 7 2
1 5 9
8 3 4
#include<bits/stdc++.h>
using namespace std;int ans, A[10], put[10], bk[10], B[10];
void dfs(int i) {if (i==7 && A[1]+A[2]+A[3]!=A[4]+A[5]+A[6]) return;if (i==8 && (A[4]+A[5]+A[6]!=A[1]+A[4]+A[7] || A[4]+A[5]+A[6]!=A[3]+A[5]+A[7])) return;if (i==9 && A[2]+A[5]+A[8]!=A[4]+A[5]+A[6]) return;if (i==10 && A[7]+A[8]+A[9]==A[2]+A[5]+A[8] && A[7]+A[8]+A[9]==A[1]+A[5]+A[9]) {ans++;for (int j=1; j<10; j++) B[j]=A[j];return;}if (put[i]) {dfs(i+1); } else {for (int j=1; j<10; j++) if (!bk[j]) {bk[j]=1, A[i]=j;dfs(i+1);bk[j]=0;}}
}
int main() {std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);for (int i=1; i<=9; i++) {cin>>A[i];if (A[i]>0) put[i]=true;}dfs(1);if (ans==1) {for (int i=1; i<=9; i++) {cout << B[i] << ' ';if (i%3==0) cout << '\n';}} else {cout << "Too Many";}return 0;
}
四、反幻方

我国古籍很早就记载着

2 9 4 
7 5 3 
6 1 8 

这是一个三阶幻方。每行每列以及对角线上的数字相加都相等。
下面考虑一个相反的问题。
可不可以用 1~9 的数字填入九宫格,使得:每行每列每个对角线上的数字和都互不相等呢?
这应该能做到。
比如:

9 1 2 
8 4 3 
7 5 6 

你的任务是搜索所有的三阶反幻方。并统计出一共有多少种。旋转或镜像算同一种。 比如:

9 1 2     7 8 9     2 1 9 
8 4 3     5 4 1     3 4 8 
7 5 6     6 3 2     6 5 7 

3120

{//答案是int row1 = m[0]+m[1]+m[2];int row2 = m[3]+m[4]+m[5];int row3 = m[6]+m[7]+m[8];int col1 = m[0]+m[3]+m[6];int col2 = m[1]+m[4]+m[7];int col3 = m[2]+m[5]+m[8];int xie1 = m[0]+m[4]+m[8];int xie2 = m[2]+m[4]+m[6];int[] p = {row1,row2,row3,col1,col2,col3,xie1,xie2};for(int i=0; i<p.length; ++i)for(int j=i+1; j<p.length; ++j){if(p[i]==p[j])return;}count++;return;
}
五、魔方状态

二阶魔方就是只有2层的魔方,只由8个小块组成。如图所示。

小明很淘气,他只喜欢3种颜色,所有把家里的二阶魔方重新涂了颜色,如下:
前面:橙色、右面:绿色、上面:黄色、左面:绿色、下面:橙色、后面:黄色
请你计算一下,这样的魔方被打乱后,一共有多少种不同的状态。
如果两个状态经过魔方的整体旋转后,各个面的颜色都一致,则认为是同一状态。

六、纸牌三角形

A,2,3,4,5,6,7,8,9 共9张纸牌排成一个正三角形(A按1计算)。要求每个边的和相等。
下图就是一种排法这样的排法可能会有很多。
如果考虑旋转、镜像后相同的算同一种,一共有多少种不同的排法呢?

对结果除以 3 再除以 2

这篇关于【回溯】B027_LQ_六角幻方 四阶幻方 九宫幻方 反幻方 魔方状态 纸牌三角形(恶心的剪枝)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/331021

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

hdu1565(状态压缩)

本人第一道ac的状态压缩dp,这题的数据非常水,很容易过 题意:在n*n的矩阵中选数字使得不存在任意两个数字相邻,求最大值 解题思路: 一、因为在1<<20中有很多状态是无效的,所以第一步是选择有效状态,存到cnt[]数组中 二、dp[i][j]表示到第i行的状态cnt[j]所能得到的最大值,状态转移方程dp[i][j] = max(dp[i][j],dp[i-1][k]) ,其中k满足c

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

【WebGPU Unleashed】1.1 绘制三角形

一部2024新的WebGPU教程,作者Shi Yan。内容很好,翻译过来与大家共享,内容上会有改动,加上自己的理解。更多精彩内容尽在 dt.sim3d.cn ,关注公众号【sky的数孪技术】,技术交流、源码下载请添加微信号:digital_twin123 在 3D 渲染领域,三角形是最基本的绘制元素。在这里,我们将学习如何绘制单个三角形。接下来我们将制作一个简单的着色器来定义三角形内的像素

状态dp总结

zoj 3631  N 个数中选若干数和(只能选一次)<=M 的最大值 const int Max_N = 38 ;int a[1<<16] , b[1<<16] , x[Max_N] , e[Max_N] ;void GetNum(int g[] , int n , int s[] , int &m){ int i , j , t ;m = 0 ;for(i = 0 ;

hdu3006状态dp

给你n个集合。集合中均为数字且数字的范围在[1,m]内。m<=14。现在问用这些集合能组成多少个集合自己本身也算。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.Inp

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

实例:如何统计当前主机的连接状态和连接数

统计当前主机的连接状态和连接数 在 Linux 中,可使用 ss 命令来查看主机的网络连接状态。以下是统计当前主机连接状态和连接主机数量的具体操作。 1. 统计当前主机的连接状态 使用 ss 命令结合 grep、cut、sort 和 uniq 命令来统计当前主机的 TCP 连接状态。 ss -nta | grep -v '^State' | cut -d " " -f 1 | sort |

hdu1010 奇偶剪枝

恰好t时间到达 import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.math.BigInteger;import java.util.Arrays;import

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停