幻方

【题目描述】
给定 N*N 个数,把它们填入 N*N 的方格中,使每行每列和两个对角线里数的和都相等。
数据保证有可行解,输出任一解即可。
【输入格式】
第一行一个整数 N。
第二行 N*N 个整数,表示要填入幻方中的数。
【输出格式】
N 行,每行 N 个整数,代表填好的幻方
【样例输入】
3
1 2 3 4 5 6 7 8 9
【样例输出】
3
2 7 6
9 5 1
4 3 8

大致是一行一行枚举搜

要加上各种减支

1.一行的和不为lim

2.开始预处理出单个数字可以参与多少和为lim的方案f[i]

显然对角线要求f[i]>3

3.改变搜索顺序,按f从小到大排序,不过这应该没什么用

4.在倒数第2行时判断最后一行可以使这一列的和等于lim,无法就不需要枚举后面的点了

(这是很重要的剪枝)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<ctime>
  6 using namespace std;
  7 struct XXX
  8 {
  9     long long x;
 10     int f;
 11 } a[17];
 12 int n;
 13 long long s[5][5],sumx[5],sumy[5],lim;
 14 bool vis[17];
 15 bool cmp(XXX x,XXX y)
 16 {
 17     return x.f>y.f;
 18 }
 19 bool judge(int y)
 20 {int i;
 21     for (i=1;i<=n*n;i++)
 22     if (vis[i]==0&&sumy[y]+a[i].x==lim) return 0;
 23     return 1;
 24 }
 25 void dfs(int x,int y)
 26 {
 27     int i,j;
 28     if (y>n)
 29     {
 30         if (sumx[x]!=lim) return;
 31         dfs(x+1,1);
 32         return;
 33     }
 34     if (x>n)
 35     {
 36         long long s1=0,s2=0;
 37         for (i=1; i<=n; i++)
 38             s1+=s[i][n-i+1],s2+=s[i][i];
 39         if (s1!=s2) return;
 40         else if (s1==s2&&s1==lim)
 41         {
 42             for (i=1; i<=n; i++)
 43             {
 44                 for (j=1; j<=n; j++)
 45                     printf("%lld ",s[i][j]);
 46                 printf("\n");
 47             }
 48             exit(0);
 49         }
 50         return;
 51     }
 52     for (i=1; i<=n*n; i++)
 53         if (vis[i]==0)
 54         {
 55             if (x==n)
 56             {
 57                 if (sumy[y]+a[i].x==lim)
 58                 {
 59                     s[x][y]=a[i].x;
 60                     sumx[x]+=a[i].x;
 61                     sumy[y]+=a[i].x;
 62                     vis[i]=1;
 63                     if ((x==y||x==n-y+1)&&a[i].f<3);
 64                     else
 65                         dfs(x,y+1);
 66                     sumx[x]-=a[i].x;
 67                     sumy[y]-=a[i].x;
 68                     vis[i]=0;
 69                 }
 70             }
 71             else
 72             {
 73                 s[x][y]=a[i].x;
 74                 sumx[x]+=a[i].x;
 75                 sumy[y]+=a[i].x;
 76                 vis[i]=1;
 77                 if ((x==y||x==n-y+1)&&a[i].f<3);
 78                 else if (x==n-1&&judge(y));
 79                 else 
 80                     dfs(x,y+1);
 81                 sumx[x]-=a[i].x;
 82                 sumy[y]-=a[i].x;
 83                 vis[i]=0;
 84             }
 85         }
 86 }
 87 int main()
 88 {
 89     int i,j,k,l;
 90     cin>>n;
 91     for (i=1; i<=n*n; i++)
 92     {
 93         scanf("%lld",&a[i].x);
 94         lim+=a[i].x;
 95     }
 96     lim/=n;
 97     if (n==4)
 98         for (i=1; i<=n*n; i++)
 99         {
100             for (j=i+1; j<=n*n; j++)
101             {
102                 for (k=j+1; k<=n*n; k++)
103                 {
104                     for (l=k+1; l<=n*n; l++)
105                     {
106                         if (a[i].x+a[j].x+a[k].x+a[l].x==lim)
107                             a[i].f++,a[j].f++,a[k].f++,a[l].f++;
108                     }
109                 }
110             }
111         }
112     if (n==3)
113         for (i=1; i<=n*n; i++)
114         {
115             for (j=i+1; j<=n*n; j++)
116             {
117                 for (k=j+1; k<=n*n; k++)
118                 {
119                     if (a[i].x+a[j].x+a[k].x==lim)
120                         a[i].f++,a[j].f++,a[k].f++;
121                 }
122             }
123         }
124     sort(a+1,a+n*n+1,cmp);
125     dfs(1,1);
126 }

 

posted @ 2017-10-13 17:29  Z-Y-Y-S  阅读(403)  评论(0编辑  收藏  举报