标题:六角幻方

    把 1 2 3 ... 19 共19个整数排列成六角形状,如下:

    * * *
   * * * *
  * * * * *
   * * * * 
    * * *

    要求每个直线上的数字之和必须相等。共有15条直线哦!

    再给点线索吧!我们预先填好了2个数字,第一行的头两个数字是:15 13,参见图【p1.png】,黄色一行为所求。

    请你填写出中间一行的5个数字。数字间用空格分开。

    这是一行用空格分开的整数,请通过浏览器提交答案,不要填写任何多余的内容(比如说明性的文字等)

解题报告:

  好久没写搜索了,,当个练习。

不难发现每一行的值的和应该是38,所以我们已经有了三个已知数字了。

根据对称性把这三个数放在每一行的开始,相当于有了三个已知行的行首,然后按行dfs,同时判断是否凑够了38,如果超了38那就直接return就行,这一点可以用附初始值为比较大的值(这里用了100000)来实现。如果还没填满这一行但是和已经大于38了  或者  都填满了并且还不是38,那就return。这应该是最优秀的剪枝了,是每一步都会有剪枝。当然如果不这样剪枝,而是直接: 每一行都填满了再判断是否等于38,也可以。

最终答案:

10 12 16
13 4 2 19
15 8 5 7 3
14 6 1 17
9 11 18

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
int a[55][55],all[55] = {0,10,13,15,0,0};
int up[55] = {0,3,4,5,4,3};
bool vis[55],ok[55][55];
bool cc() {
if(a[1][2]+a[2][2]+a[3][2]+a[4][1]!=38) return 0;
if(a[1][3]+a[2][3]+a[3][3]+a[4][2]+a[5][1]!=38) return 0;
if(a[2][4]+a[3][4]+a[4][3]+a[5][2]!=38) return 0;
if(a[3][5]+a[4][4]+a[5][3]!=38) return 0;

if(a[1][3]+a[2][4]+a[3][5]!=38) return 0;
if(a[1][2]+a[2][3]+a[3][4]+a[4][4]!=38) return 0;
if(a[1][1]+a[2][2]+a[3][3]+a[4][3]+a[5][3]!=38) return 0;
if(a[2][1]+a[3][2]+a[4][2]+a[5][2]!=38) return 0;
if(a[3][1]+a[4][1]+a[5][1]!=38) return 0;
return 1;
}
bool check() {
if(a[1][2]+a[2][2]+a[3][2]+a[4][1]!=38 && a[1][2]+a[2][2]+a[3][2]+a[4][1]<100000) return 0;
if(a[1][3]+a[2][3]+a[3][3]+a[4][2]+a[5][1]!=38 && a[1][3]+a[2][3]+a[3][3]+a[4][2]+a[5][1]<100000) return 0;
if(a[2][4]+a[3][4]+a[4][3]+a[5][2]!=38 && a[2][4]+a[3][4]+a[4][3]+a[5][2]<100000) return 0;
if(a[3][5]+a[4][4]+a[5][3]!=38 && a[3][5]+a[4][2]+a[5][3]<100000) return 0;

if(a[1][3]+a[2][4]+a[3][5]!=38 && a[1][3]+a[2][4]+a[3][5]<100000) return 0;
if(a[1][2]+a[2][3]+a[3][4]+a[4][4]!=38 && a[1][2]+a[2][3]+a[3][4]+a[4][4]<100000) return 0;
if(a[1][1]+a[2][2]+a[3][3]+a[4][3]+a[5][3]!=38 && a[1][1]+a[2][2]+a[3][3]+a[4][3]+a[5][3]<100000) return 0;
if(a[2][1]+a[3][2]+a[4][2]+a[5][2]!=38 && a[2][1]+a[3][2]+a[4][2]+a[5][2]<100000) return 0;
if(a[3][1]+a[4][1]+a[5][1]!=38 && a[3][1]+a[4][1]+a[5][1]<100000) return 0;
return 1;
}
void dfs(int x,int y) {
if(x == 6) {
if(cc() == 0) return;
for(int i = 1; i<=5; i++) {
for(int j = 1; j<=up[i]; j++) {
printf("%d ",a[i][j]);
}
printf("\n");
}
return;
}
if(check() == 0) return;
if(ok[x][y]) {
dfs(x,y+1);return;
}
for(int i = 1; i<=19; i++) {
if(vis[i]) continue;
if(all[x] + i > 38) continue;
if(y == up[x]) {
if(all[x] + i != 38) continue;
else {
all[x] += i;
vis[i] = 1;
a[x][y] = i;
dfs(x+1,1);
a[x][y] = 100000;
all[x] -= i;
vis[i] = 0;
return;
}
}
vis[i] = 1;
all[x] += i;
a[x][y] = i;
dfs(x,y+1);
a[x][y] = 100000;
vis[i] = 0;
all[x] -= i;
}
}
int main()
{
for(int i = 1; i<=5; i++) {
for(int j = 1; j<=5; j++) a[i][j] = 100000;
}
a[1][1]=10;a[2][1]=13;a[3][1]=15;
ok[1][1]=1;ok[2][1]=1;ok[3][1]=1;
vis[10]=1;vis[13]=1;vis[15]=1;
dfs(1,1);
return 0 ;
}
//19:00-19:20

/*
10 12 16
13 4 2 19
15 8 5 7 3
14 6 1 17
9 11 18

*/