1. 程式人生 > 其它 >洛谷 P1406方格填數 題解

洛谷 P1406方格填數 題解

題意

給一個n * n的方格矩陣,還有n * n個整數,讓你將這些整數填入矩陣,使得每行每列每個對角線上整數的和都相等。


輸入格式

第一行一個整數n.(1<=n<=4)

第二行n*n個整數 ai (-10^8 <=ai <= 10^8)


輸出格式

第一行一個整數s 代表每行每列每個對角線的和值

接下來輸出一個n * n的矩陣,表示填數方案。

資料保證有解,可能存在多種方案,輸出字典序最小的(將每行順次相連之後,字典序最小)

樣例輸入

 3
 1 2 3 4 5 6 7 8 9

樣例輸出

 15
 2 7 6
 9 5 1
 4 3 8

題解

首先可以確定,每行、每列、每個對角線的值 sum = 矩陣中所有元素之和除以 n。

因為題目要求按字典序輸出,所以先把陣列從小到大排序

從第一個數進行深度優先搜尋,最後輸出答案,用exit(0)直接結束程式(return ;的時間較長,需要一步一步地往回回溯)。

如何優化? => 可以進行剪枝:在每一行結束、每一列結束或每一對角線結束時可以用一個函式judge判斷這一行、列或對角線之和是否等於 sum。

程式碼

#include <bits/stdc++.h>
using namespace std;

int n, sum;
int b[5][5],v[25], a[25];

void printAns()    //輸出答案
{
 printf("%d\n", sum);
 for(int i = 1; i <= n; i++)
 {
     for(int j = 1; j <= n; j++) 
         printf("%d ", b[i][j]);
     printf("\n");
 }
}

bool check(int x, int y, int i)
{
 if(y == n)   //判斷每一行
 {
     int tsum = a[i];
     for(int j = 1; j < n; j++)
         tsum += b[x][j];
     if(tsum != sum) return false;
 }
 if(x == n)   //判斷每一列
 {
     int tsum = a[i];
     for(int j = 1; j < n; j++)
         tsum += b[j][y];
     if(tsum != sum) return false;
 }
 if(x == n && y == n)   //判斷正對角線
 {
     int tsum = a[i];
     for(int j = 1; j < n; j++)
         tsum += b[j][j];
     if(tsum != sum) return false;
 }
 if(x == n && y == 1)   //判斷負對角線
 {
     int tsum = a[i];
     for(int j = 1; j < n; j++)
         tsum += b[j][n - j + 1];
     if(tsum != sum) return false;
 }
 return true;
}

void dfs(int x, int y)
{
 if(x == n + 1)   //如果搜到了x+1行,說明已經搜尋完畢,直接輸出。
 {
     printAns();
     exit(0);
 }
 for(int i = 1; i <= n * n; i++)
 {
     if(!v[i])
     {
         if(!check(x, y, i)) continue;    //用judge函式進行優化剪枝
         v[i] = 1;   //標記為已訪問
         b[x][y] = a[i];    //將a[i]新增進答案
         if(y == n)  dfs(x + 1, 1);   //如果到達某一行的最後一列,就搜尋下一行
         else dfs(x, y + 1);   //如果沒有到達某一行的最後一列,就搜尋下一列
         v[i] = 0;     //  回溯
     }
 }
 
}

int main()
{
 scanf("%d", &n);
 for(int i = 1; i <= n * n; i++) 
 {
     scanf("%d", &a[i]);
     sum += a[i];
 }
 sum = sum / n;  
 sort(a + 1, a + 1 + n * n);   //因為是字典序小的先輸出,所以要先進行排序
 
 dfs(1,1);
 return 0;
}