【蓝桥杯 - 真题】六角幻方(dfs+剪枝)
標題:六角幻方
? ? 把 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*/?
總結
以上是生活随笔為你收集整理的【蓝桥杯 - 真题】六角幻方(dfs+剪枝)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 办信用卡未通过预审 信用卡申请失败从这里
- 下一篇: 【牛客OI周赛7-普及组ABCD 非官方