标题:六角幻方
把 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*/