(DFS)九宫幻方

  历届试题 九宫幻方  

时间限制:1.0s   内存限制:256.0MB

    

问题描述

  小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将1~9不重复的填入一个3*3的矩阵当中,使得每一行、每一列和每一条对角线的和都是相同的。

  三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:“二四为肩,六八为足,左三右七,戴九履一,五居其中”,通过这样的一句口诀就能够非常完美的构造出一个九宫格来。

  4 9 2
  3 5 7
  8 1 6


  有意思的是,所有的三阶幻方,都可以通过这样一个九宫格进行若干镜像和旋转操作之后得到。现在小明准备将一个三阶幻方(不一定是上图中的那个)中的一些数抹掉,交给邻居家的小朋友来进行还原,并且希望她能够判断出究竟是不是只有一个解。

  而你呢,也被小明交付了同样的任务,但是不同的是,你需要写一个程序~

输入格式

  输入仅包含单组测试数据。
  每组测试数据为一个3*3的矩阵,其中为0的部分表示被小明抹去的部分。
  对于100%的数据,满足给出的矩阵至少能还原出一组可行的三阶幻方。

输出格式

  如果仅能还原出一组可行的三阶幻方,则将其输出,否则输出“Too Many”(不包含引号)。

样例输入

0 7 2
0 5 0
0 3 0

样例输出

6 7 2
1 5 9
8 3 4

数据规模和约定

  峰值内存消耗(含虚拟机) < 256M
  CPU消耗 < 1000ms




  请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。


  注意:
  main函数需要返回0;
  只使用ANSI C/ANSI C++ 标准;
  不要调用依赖于编译环境或操作系统的特殊函数。
  所有依赖的函数必须明确地在源文件中 #include <xxx>
  不能通过工程设置而省略常用头文件。


  提交程序时,注意选择所期望的语言类型和编译器类型。


  --------------


  笨笨有话说:
  我最喜欢这类题目了。既然九宫幻方一共也没有多少,我就不辞辛劳地一个一个写出来好了。
  也不能太过分,好歹用个数组。

// 这道题不难,关键在于剪枝,不剪枝的话,应该只能过70%左右
#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<bitset>
#include<iomanip>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define eps (1e-8)
#define MAX 0x3f3f3f3f
#define u_max 1844674407370955161
#define l_max 9223372036854775807
#define i_max 2147483647
#define re register
#define pushup() tree[rt]=max(tree[rt<<1],tree[rt<<1|1])
#define nth(k,n) nth_element(a,a+k,a+n);  // 将 第K大的放在k位
#define ko() for(int i=2;i<=n;i++) s=(s+k)%i // 约瑟夫
#define ok() v.erase(unique(v.begin(),v.end()),v.end()) // 排序,离散化
#define Catalan C(2n,n)-C(2n,n-1)  (1,2,5,14,42,132,429...) // 卡特兰数
using namespace std;

inline int read(){
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' & c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}

typedef long long ll;
const double pi = atan(1.)*4.;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int M=63;
const int N=1e5+5;
int n=0,a[5][5],v[10],b[10],p=0,sum=0,c[5][5];

bool fun(){
    int ans=(a[0][0]+a[0][1]+a[0][2]);
    if(ans==(a[1][0]+a[1][1]+a[1][2])
       &&ans==(a[2][0]+a[2][1]+a[2][2])
       &&ans==(a[0][0]+a[1][0]+a[2][0])
       &&ans==(a[0][1]+a[1][1]+a[2][1])
       &&ans==(a[0][2]+a[1][2]+a[2][2])
       &&ans==(a[0][0]+a[1][1]+a[2][2])
       &&ans==(a[0][2]+a[1][1]+a[2][0]))
        return true;
    return false;
}
map<int,int>mapp;
void dfs(int num){
    if(sum>2) return ;   //  剪枝1

    for(int i=0;i<3;i++){        ------    // 剪枝2,每行,列,对角线和应该为15
        int cut=0,leap=0;          .
        for(int j=0;j<3;j++){      .
            if(a[i][j]==0){
                leap=1;
                break;
            }
            cut+=a[i][j];          .
        }                          .
        if(!leap&&cut!=15)
            return ;
    }

    for(int i=0;i<3;i++){
        int cut=0,leap=0;          .
        for(int j=0;j<3;j++){      .
            if(a[j][i]==0){
                leap=1;
                break;
            }
            cut+=a[j][i];
        }
        if(!leap&&cut!=15)         .
            return ;               .
    }

    int cut=0,leap=0;
    for(int i=0;i<3;i++){
        if(a[i][i]==0){            .
            leap=1;                .
            break;
        }
        cut+=a[i][i];
    }
    if(!leap){
        if(cut!=15)
            return ;               '
    }                              .

    cut=0,leap=0;
    for(int i=0;i<3;i++){
        if(a[i][2-i]==0){
            leap=1;
            break;
        }
        cut+=a[i][2-i];            .
    }                              .
    if(!leap){
        if(cut!=15)
            return ;               .
    }                           -------


    if(num==n){
        if(fun()){
            int ans=0;
            for(int i=0;i<3;i++)
                for(int j=0;j<3;j++){
                    ans=ans*10+a[i][j];
                    c[i][j]=a[i][j];
                }
            if(!mapp.count(ans)){
                mapp[ans]=1;
                sum++;
            }
        }
        return ;
    }
    for(int j=0;j<3;j++){
        for(int k=0;k<3;k++){
            if(a[j][k]==0){
                for(int i=0;i<p;i++){
                    if(v[b[i]]) continue;
                    v[b[i]]=1;
                    a[j][k]=b[i];
                    dfs(num+1);
                    a[j][k]=0;
                    v[b[i]]=0;
                }
            }
        }
    }
}
int main(){
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++){
            scanf("%d",&a[i][j]);
            if(a[i][j]==0)
                n++;
            else{
                v[a[i][j]]=1;
            }
        }
    for(int i=1;i<=9;i++){
        if(v[i]) continue;
        b[p++]=i;
    }
    dfs(0);
    if(sum==1){
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                printf("%d ",c[i][j]);
            }
            printf("\n");
        }
    }
    else
        printf("Too Many\n");
    return 0;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值