[蓝桥杯2015决赛]四阶幻方

题目描述
把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

就可以算为两种不同的方案。
分析
第一眼以为还是全排列,但是仔细一看16!挂机到赛后可能都跑不出来,只能dfs+剪枝了。这里采用一维数组来模拟二维数组的排列,跑起来还是蛮快的。

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 2e5 + 10;

int n;
int a[20];
bool st[20];
bool used[20];
int ans;

void dfs(int u)
{
    if(u > n ){
        if(a[13] + a[14] + a[15] + a[16] != 34) return;
        if(a[4] + a[8] + a[12] + a[16] != 34)   return ;
        if(a[1] + a[6] + a[11] + a[16] != 34)   return ;
        ans ++;
        return ;
    }

    if(u > 4){
        if(a[1] + a[2] + a[3] + a[4] != 34) return;
    }

    if(u > 13){
        if(a[4] + a[7] + a[10] + a[13] != 34)   return ;
        if(a[1] + a[5] + a[9] + a[13] != 34) return;
    }

    if(u > 14){
        if(a[2] + a[6] + a[10] + a[14] != 34) return;
    }

    if(u > 15){
        if(a[3] + a[7] + a[11] + a[15] != 34) return;
    }

    if(u > 8){
        if(a[5] + a[6] + a[7] + a[8] != 34) return;
    }

    if(u > 12){
        if(a[9] + a[10] + a[11] + a[12] != 34) return;
    }

    for(int i = 2; i <= n; i ++ ){
        if(!used[i]){
            a[u] = i;
            used[i] = true;
            dfs(u + 1);
            used[i] = false;
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    n = 16;
    a[1] = 1;
    used[1] = true;
    dfs(2);

    cout << ans << endl;
    return 0;
}

posted @ 2023-04-27 00:23  车车学不完  阅读(42)  评论(0)    收藏  举报