[解题报告][搜索+剪枝技巧]幻方

【Description】
请解决一个 N 阶幻方。(N=3或4)
为了凑够 15 字补一个幻方的简介好了。给定 N*N 个数,把它们填入 N*N 的方格中,使每
行每列和两个斜对角线里数的和都相等。
【Input】
第一行一个正整数 N
第二行 N*N 个整数,代表要填入幻方中的数
【Output】
N 行每行 N 个整数,用空格隔开,代表填好的幻方。
如果有多组解,输出任意一组即可。
保证有解。
【Sample Input1】
3
9 9 9 9 9 9 9 9 9
【Sample Output1】
9 9 9
9 9 9
9 9 9
【Sample Input2】
3
1 2 3 4 5 6 7 8 9
【Sample Output2】
2 7 6
9 5 1
4 3 8

思路:

1.如果n=3,可以暴力枚举,复杂度为O(9!)

2.n=4时,直接暴力4*4的话一定会挂,可以只暴力8个格子

          # # # #

          # 1 # 8

          # 6 2 7

          # 5 4 3

剪枝1:只搜8个格子(上)

剪枝2:按照一定的顺序搜索,当搜索到一些特定的格子就能推算出某个#的数值,如果#不在可用数字范围内,可以直接return

优化1:记录每个数字出现的个数,判断是否在可用范围内时直接判断个数,注意最好不要用map(似乎会消耗大量时间),可以用unordered_map或者自己离散化。

幻方和=所有数字总和/n

代码:

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <algorithm>
  4 #include <map>
  5 #include <ctime>
  6 #include <cstring>
  7 using namespace std;
  8 int pl[20],use[20];
  9 int n,pn,sum;
 10 int hf[5][5];
 11 int mm[20],mmct[20];
 12 int mp=0;
 13 #define covidx(x,y) (x-1)*4+(y-1)
 14 void prints()
 15 {
 16     for(int i=1; i<=n; i++)
 17         for(int j=1; j<=n; j++)
 18             {
 19                 printf("%d%c",hf[i][j],j==n?‘\n‘:‘ ‘);
 20             }
 21 }
 22 inline int getid(int a)
 23 {
 24     for(int i=0; i<mp; i++)
 25         {
 26             if(mm[i]==a) return i;
 27         }
 28     return 19;
 29 }
 30 inline int check()
 31 {
 32     int t1=0,t2=0,t3=0,t4=0;
 33     for(int i=1; i<=n; i++)
 34         {
 35             t1+=hf[i][i];
 36             t2+=hf[i][n-i+1];
 37             for(int j=1; j<=n; j++)
 38                 {
 39                     t3+=hf[i][j];
 40                     t4+=hf[j][i];
 41                 }
 42             if(t3!=t4 || t3!=sum || t4!=sum) return 0;
 43             else if(i!=n)
 44                 t3=t4=0;
 45         }
 46     if(t2!=t1) return 0;
 47     if(t3!=t2) return 0;
 48     if(t2!=sum) return 0;
 49     return 1;
 50 }
 51 void fuck3(int x,int y)
 52 {
 53
 54     if(x==4)
 55         {
 56             if(check())
 57                 {
 58                     prints();
 59                     exit(0);
 60                 }
 61             else
 62                 return;
 63         }
 64     int tx,ty;
 65     for(int i=1; i<=pn; i++)
 66         {
 67             if(!use[i])
 68                 {
 69                     use[i]=1;
 70                     hf[x][y]=pl[i];
 71                     if(y==3)
 72                         {
 73                             ty=1;
 74                             tx=x+1;
 75                         }
 76                     else
 77                         {
 78                             ty=y+1;
 79                             tx=x;
 80                         }
 81                     fuck3(tx,ty);
 82                     use[i]=0;
 83                 }
 84         }
 85 }
 86
 87 /*
 88  3 6 8 8
 89 #7 1 8 8
 90  7 6 2 7
 91  5 5 4 3
 92
 93  1  2  3  4
 94  5  6  7  8
 95  9  10 11 12
 96  13 14 15 16
 97 */
 98 int xyidx[9][2]= {{-1,-1},{2,2},{3,3},{4,4},{4,3},{4,2},{3,2},{3,4},{2,4}};
 99 int deps[16][8]=
100 {
101     {1,2,3},{1,6,5},{-1,-2,-4},{8,7,3},
102     {-1,-9,-13},{0},{-5,1,8},{0},
103     {6,2,7},{0},{0},{0},
104     {5,4,3},{0},{0},{0}
105 };
106 int lin[16][4]=
107 {
108     {0},{0},{0},{3},
109     {0},{0},{4},{7},
110     {5},{2},{0},{9},
111     {0},{13},{0},{1}
112 };
113
114
115
116 int prelin(int idx)
117 {
118     int i,j;
119     i=0;
120     if(idx>0)
121         idx=(xyidx[idx][0]-1)*4+xyidx[idx][1]-1;
122     else
123         idx=-idx;
124     while(lin[idx][i]!=0)
125         {
126             int cpa=lin[idx][i];
127             int x=(cpa-1)/4+1;
128             int y=(cpa-1)%4+1;
129             int nsum=0;
130             j=0;
131             cpa-=1;
132             while(deps[cpa][j]!=0)
133                 {
134                     int dalao=deps[cpa][j],x,y;
135                     if(dalao>0)
136                         {
137                             x=xyidx[dalao][0];
138                             y=xyidx[dalao][1];
139                         }
140                     else
141                         {
142                             dalao=-dalao;
143                             dalao-=1;
144                             x=dalao/4+1;
145                             y=dalao%4+1;
146                         }
147                     nsum+=hf[x][y];
148                     j++;
149                 }
150             int id;
151             if(mmct[id=getid(sum-nsum)]>0)
152                 {
153                     hf[x][y]=sum-nsum;
154                     mmct[id]--;
155                     prelin(-(covidx(x,y)));
156                 }
157             else
158                 {
159                     return 0;
160                 }
161             i++;
162         }
163     return 1;
164 }
165 void dfs4(int idx)
166 {
167     if(idx==9)
168         {
169             if(check())
170                 {
171                     prints();
172                     exit(0);
173                 }
174             else
175                 {
176                     return;
177                 }
178         }
179     //给idx填数
180     int x=xyidx[idx][0];
181     int y=xyidx[idx][1];
182     int bnaive[20];
183     memcpy(bnaive,mmct,sizeof(mmct));
184     int id;
185     for(int i=1; i<=pn; i++)
186         {
187             if(mmct[id=getid(pl[i])]>0)
188                 {
189                     mmct[id]--;
190                     hf[x][y]=pl[i];
191                     if(prelin(idx)==0)
192                         {
193                             memcpy(mmct,bnaive,sizeof(mmct));
194                             continue;
195                         }
196                     dfs4(idx+1);
197                     memcpy(mmct,bnaive,sizeof(mmct));
198                 }
199         }
200 }
201 int main()
202 {
203     //freopen("magicsquare.in","r",stdin);
204     //freopen("magicsquare.out","w",stdout);
205     scanf("%d",&n);
206     pn=n*n;
207     for(int i=1; i<=pn; i++)
208         {
209             scanf("%d",&pl[i]);
210             sum+=pl[i];
211         }
212     sort(&pl[1],&pl[pn+1]);
213     if(n==3)
214         fuck3(1,1);
215     else
216         {
217             sum/=4;
218             for(int i=1; i<=pn; i++)
219                 {
220                     int id;
221                     if((id=getid(pl[i]))==19)
222                         {
223                             mm[mp]=pl[i];
224                             mmct[mp]=1;
225                             mp++;
226                         }
227                     else
228                         {
229                             mmct[id]++;
230                         }
231                 }
232             dfs4(1);
233         }
234 }
时间: 2024-08-10 03:42:09

[解题报告][搜索+剪枝技巧]幻方的相关文章

NOIP2009解题报告

09年的题总体来说 没有难题,但是每道题除了第一题都要认真的慢慢写才能AC, 第一题: R国和S国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动. 历经艰险后,潜伏于S国的R国间谍小C终于摸清了S国军用密码的编码规则:1. S国军方内部欲发送的原信息经过加密后在网络上发送,原信息的内容与加密后所的内容均由大写字母‘A’—‘Z’构成(无空格等其他字母).2. S国对于每个字母规定了对应的“密字”.加密的过程就是将原信息中的所有字母替换为其对应的“密字”.3. 每个字母只对应一个唯一的“密字

济南-1030试题解题报告

By shenben 本解题报告解析均为100分解题思路. 上午 T1 题意:从1− n中找一些数乘起来使得答案是一个完全平方数,求这个完全平方数 最大可能是多少. 解析: 1.  质因数分解 2.  1->n用质因数指数的相加的形式将1*n累乘起来 3.  扫一遍指数为奇数的质因数都-1,偶数的不变 4.  快速幂乘一遍,同时取模 T2 题意:有n个数,随机选择一段区间,如果这段区间的所有数的平均值在[L,R]中则 你比较厉害.求你比较厉害的概率 解析:(暴力枚举 40分) 100分需要推式子

洛谷OJ P1074 靶形数独 解题报告

洛谷OJ P1074 靶形数独 解题报告 by MedalPluS 题目描述  小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目. 靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有 9 个 3 格宽×3 格高的小九宫格(用粗黑色线隔开的).在这个大九宫格中,有一些数字是已知的,根据这些数字,利用逻辑推理,

NOIP2015 解题报告

过了这么久才来发解题报告,蒟蒻实在惭愧 /w\ Day1 T1 [思路] 模拟 [代码] 1 #include<iostream> 2 #include<cstring> 3 #include<queue> 4 #include<cmath> 5 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 6 using namespace std; 7 8 const int maxn = 50; 9 10 int G[

NOIP2004 解题报告

第一题:津津的零花钱一直都是自己管理.每个月的月初妈妈给津津300元钱,津津会预算这个月的花销,并且总能做到实际花销和预算的相同. 为了让津津学习如何储蓄,妈妈提出,津津可以随时把整百的钱存在她那里,到了年末她会加上20%还给津津.因此津津制定了一个储蓄计划:每个月的月初,在得到妈妈给的零花钱后,如果她预计到这个月的月末手中还会有多于100元或恰好100元,她就会把整百的钱存在妈妈那里,剩余的钱留在自己手中. 例如11月初津津手中还有83元,妈妈给了津津300元.津津预计11月的花销是180元,

【LeetCode】Symmetric Tree 解题报告

Symmetric Tree 解题报告 [LeetCode] https://leetcode.com/problems/symmetric-tree/ Total Accepted: 106639 Total Submissions: 313969 Difficulty: Easy Question Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). For

洛谷OJ P1433 吃奶酪 解题报告

洛谷OJ P1433 吃奶酪 解题报告 by MedalPluS 题目描述 房间里放着n块奶酪.一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在(0,0)点处. 输入描述 第一行一个数n  (n<=15)接下来每行2个实数,表示第i块奶酪的坐标.两点之间的距离公式=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) 输出描述 一个数,表示要跑的最少距离,保留2位小数. 分析 这题很明显就是一个搜索题,枚举一下1_n的全排列,然后从0开始,按照排列一个一个算,时间

【解题报告】Tempter of the Bone(DFS)

解题报告——Tempter of the Bon 问题描述 Time Limit: 1000ms Memory Limit: 32768KB 64-bit integer IO format: %I64d      Java class name: Main The doggie found a bone in an ancient maze, which fascinated him a lot. However, when he picked it up, the maze began to

【百度之星2014~初赛(第二轮)解题报告】Chess

声明 笔者最近意外的发现 笔者的个人网站http://tiankonguse.com/ 的很多文章被其它网站转载,但是转载时未声明文章来源或参考自 http://tiankonguse.com/ 网站,因此,笔者添加此条声明. 郑重声明:这篇记录<[百度之星2014~初赛(第二轮)解题报告]Chess>转载自 http://tiankonguse.com/ 的这条记录:http://tiankonguse.com/record/record.php?id=667 前言 最近要毕业了,有半年没做