第十屆藍橋杯C語言校選難題
題目:填入0~9的數字。
要求:連續的兩個數字不能相鄰(左右、上下、對角都算相鄰)一共有多少種可能的填數方案?
請填寫表示方案數目的整數。
注意:你提交的應該是一個整數,不要填寫任何多餘的內容或說明性文字。
程式碼構成如下
頭部:
#include <stdio.h>
#define ROW 3 // 行數
#define COL 4 // 列數
int sum = 0; // 可以成立的排列組合方案個數
迴圈遍歷陣列,當前位置的數字是否和其他存放位置的一樣。
// 填入的數字是否存在相同數字
int isT(int arr[][COL], int row, int col)
{
// 迴圈所有陣列位置
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
// 判斷是否是自身位置, 因為自身位置一定等於自身
if (row == i && col == j)
continue;
// 判斷數字是否相同 相同則返回真
if (arr[i][j] == arr[row][col])
return true;
}
}
// 都不相同返回假
return false;
}
判斷該數字的相鄰位置是否有連續數字,且當前數字是否重複出現。
// 填入的數字是否成立
int isReal(int arr[][COL], int row, int col)
{
//迴圈相鄰的位置
for (int i = row - 1; i <= row + 1; i++)
{
for (int j = col - 1; j <= col + 1; j++)
{
//過濾九宮格超出陣列範圍的部分
if (j >= 0 && j<COL && i >= 0 && i<ROW)
{
//判斷是否相鄰 且 是否含有重複數字
if ( arr[i][j] == arr[row][col] + 1
|| arr[i][j] == arr[row][col] - 1
|| isT(arr,row,col) )
{
return 0;
}
}
}
}
return 1;
}
遞迴函式
數字填充遞迴路徑 , 相當於將二維陣列看成一位陣列,從最後一位開始變更數字,暴力破解的方式填充數字
//遞迴的函式,用於暴力找出所有情況
void def(int arr[][COL], int row, int col, int num) //num為存放了多少個數字 相當於樹的深度
{
num++; //當前數字個數
if (row > 2 || row<0 || col>3 || col < 0)//防止超出陣列範圍
{
return;
}
for (int i = 0; i < 10; i++)
{
arr[row][col] = i;
// print(arr); //想看每一步的遞迴過程,請解開此註釋
if (isReal(arr, row, col) && arr[row][col + 1] != -3) //此處-3作為不可存放
def(arr, row, col + 1, num); //往右遞迴
if (isReal(arr, row, col) && arr[row + 1][0] != -3)
def(arr, row + 1, 0, num); //往下遞迴
if (num == 10 && isReal(arr, row, col)) //已經存放10個數字,同時達到題目要求條件
{
// print(arr); //想看每一步成功填入的過程,請解開此註釋
sum++;
}
}
arr[row][col] = -2; //待填入的方格用-2表示
}
主函式
void main()
{
// 賦值為-3 代表著是方塊不可寫入數字
int arr[ROW][COL] = { 0 };
for (int i = 0; i < 3; i++) // -2為待填入放個陣列
for (int j = 0; j < 4; j++)
arr[i][j] = -2;
arr[0][0] = -3; //-3禁止填入的位置,相當於牆
arr[ROW - 1][COL - 1] = -3;
def(arr, 0, 1, 0);
printf("排列方式為%d種 \n", sum);
}
用來測試結果是否為真的程式碼
void print(int arr[][COL])
{
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
printf("%2d ", arr[i][j]);
}
printf("\n");
}
printf("\n");
}