1. 程式人生 > >數獨 遞迴求解(C語言)

數獨 遞迴求解(C語言)

遞迴求解數獨(C語言)

本程式採用c語言編寫,作用是獲得一個數獨的解。

經測試,計算普通數獨時間花費不大於0.02秒。
計算“世界最難數獨”時間花費約為0.05秒。
計算效率中等,有待提高。

程式核心函式為place(),作用為遞迴設定下一個位置的值。

輸入中,1-9會被認為是數獨中的已有元素,0會被認為是空白元素。
輸入會自動忽略所有的空格和回車等非數字,輸入例子如下。可以多行分開輸入也可以在一行輸入,程式會自動擷取最前81個數字,以下輸入案例都是被允許的。

輸入例項:
1200000300000045600000789 123123  412
1 2 3 4 5 6 7 8 9  1231 1231    132
{123}123123412541241230123120000000000001231230

附:世界最難數獨
    800 000 000
    003 600 000
    070 090 200
    -----------
050 007 000 000 045 700 000 100 030 ----------- 001 000 068 008 500 010 090 000 400

程式原始碼:

/*
    Author:[email protected]
    date:20160923 version:1.0
    用途:求解陣列
    編譯器:GCC
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define RUNTIMES 1.0  //用於測試重複解某個題的次數
#define MAXRESULT 1     //設定每個數獨題目取得解的數目,有自己編的題目可能有多個解
typedef unsigned char intu; //定義新變數型別intu,實質為unsigned char ,佔1位元組,操作會省點時間 int place(intu (*array)[9],short int pos,intu num ); //核心程式,遞迴設定下一個位置的值 //pos為按橫行排列依次的順序,如pos(1,1)=0; pos(2,3)=9*(2-1)+(3-1)=11; //當pos為-1時,是啟動遞迴程式計算數獨 int input(intu (*array)[9]); //單字元模式輸入數獨,格式沒有要求,會自動忽略所有非數字,數字數量大於81時自動結束 int print(intu (*array
)[9]); //列印數獨陣列 int copyArray(intu (*array)[9],intu (*copy)[9]); //複製陣列的副本 int isIllegal(intu (*array)[9],intu x,intu y,intu num ); //驗證在(x,y)位置放置num是否可行,不可行則返回1,可行則返回0 static long countOfPlace=0; //計數器,記錄place函式執行次數 static long countOfPrint=0; //記錄print函式執行次數 static long countOfResult=0; //記錄已經計算出來的結果數 int main() { clock_t start,stop; intu a[9][9]; input(a); print(a); start=clock();//記錄開始時間 { int i; for(i=1; i<=RUNTIMES; i++)//重複多次執行數獨計算,統計所耗時間的平均值 { place(a,-1,0); //這才是核心!!pos=-1,啟動計算數獨陣列a,num數值不影響 } } stop=clock();//記錄結束時間 long totalTime=(stop-start)/CLOCKS_PER_SEC; printf("totalTime= %f second\n",totalTime/RUNTIMES); printf("CountOfPlace=%ld\n",countOfPlace); getch(); return 0; } int copyArray(intu (*array)[9],intu (*copy)[9]) { intu *a=(intu *)array,*c=(intu *)copy; int i; for(i=0; i<81; i++) { *c=*a; c++; a++; } return 0; } int input(intu (*array)[9]) { intu *a=(intu *)array; char c;//採用單字元模式輸入,變數 c臨時儲存輸入的字元 int i; for(i=1; i<=81; i++) { do { scanf("%c",&c); } while(c<'0'|| c>'9'); //如果輸入的那個字元不是數字就把下一個賦值給c,直到c是數字 //上面的迴圈的作用也就是跳過所有非數字,包括空格,回車等。 *a=c-48; //把數值寫入到陣列中 a++; } return 0; } int print(intu (*array)[9]) { countOfPrint++; intu *a=(intu *)array; printf("\n"); printf("PrintCount=%ld\n",countOfPrint); printf("ResultCount=%ld\n",countOfResult ); int i; for(i=1; i<=81; i++) { printf("%2d",*a); a++; if(i%9==0) printf("\n"); } return 0; } int isIllegal(intu (*array)[9],intu x,intu y,intu num ) { intu i,j; intu *a=(intu*)array; for(i=1; i<=9; i++) { for(j=1; j<=9; j++) { //迴圈i,j ,得到的指標a指向(i,j)元素 //當(x為i 或者 y為i 或者(i,j)在(x,y)所在的九宮格)並且(i,j)不是(x,y)點時,為直接影響放置元素合法性的位置 if (!(x==i&&j==y) && (x==i || j==y|| ( (x-1)/3==(i-1)/3 && (y-1)/3==(j-1)/3 ))) { //如果在以上區域已經存在該數字,則返回非法1 if(*a==num) return 1; } a++; } } //不存在非法,返回合法0 return 0; } int place(intu (*array)[9],short int pos,intu num ) /* 1.在pos位置放置num 2.將pos移動到下一個空白, 如果pos超界則表示已經求出結果 3.沒有超界就判斷1-9在當前位置的合理性 如果合理就呼叫place進行下一輪遞迴 */ { countOfPlace++; //函式執行次數計數器,除錯用,可以不理睬 intu copy[9][9]; //定義一個數組儲存數獨副本 intu * c=(intu* )copy; //一個指標指向副本陣列起始元素,操作方便 copyArray(array,copy); //複製原始陣列到副本數組裡 if(pos<0) countOfResult=0; //pos為-1表示初始化,把解的數量設定為零 if(pos>=0 ) *(c+pos)=num; //pos>=0是合法的,在pos位置放置數字num if(countOfResult>=MAXRESULT) return 0; //如果求得解的數量已經符合要求,那麼不用繼續執行了 //下面的do while迴圈是使pos指向下一個為0的元素 do { pos++; if(pos>80) //pos最大值為80,若大於80則說明已經求得了一個結果 { countOfResult++; //結果數量計數器 print(copy); //列印結果 return 0; } } while( *(c+pos)); intu n,x,y; //n表示在下個位置要放的數字 for(n=1; n<=9; n++) { x=pos/9+1; //求得pos對應的行號x,列號y y=pos%9+1; if(!isIllegal(copy,x,y,n)) //如果在下個位置可以放置數字n place(copy,pos,n); //那麼呼叫place函式放置n,並開始新一輪的遞迴 } return -1; }

相關推薦

求解C語言

遞迴求解數獨(C語言) 本程式採用c語言編寫,作用是獲得一個數獨的解。 經測試,計算普通數獨時間花費不大於0.02秒。 計算“世界最難數獨”時間花費約為0.05秒。 計算效率中等,有待提高。 程式核心函式為place(),作用為遞迴設定下一個位置的值。

整數劃分的非演算法C語言

記錄點滴成長: 整數劃分的非遞迴演算法 例如將整數6劃分為如下: 65 14 2 4 1 13 3 3 2 1 3 1 1 12 2 2 2 2 1 1 2 1 1 1 11 1 1 1 1 1如6有11個劃分。 #include "stdio.h"void  Div

斐波那契數列的迭代實現與實現c語言

遞迴實現 #include<stdio.h> int Fib(int n){ // 自定義函式 if(n<0) return -1; else if(n==0) return 0; else if(n==1)

二叉樹插入和刪除操作的實現c語言

連結串列和陣列是最常見的資料結構,對於資料結構來說,查詢(Find),最大最小值(FindMin,FindMax),插入(Insert)和刪除(Delete)操作是最基本的操作。對於連結串列和陣列來說,這些操作的時間界為O(N),其中N為元素的個數。陣列的插入和刪除需要對其他

歸併排序的實現C語言

前言:理論很枯燥、文字更煩人,但是這裡將理論知識告訴大家並不是讓大家一上來就看乾巴巴的文字,因為我在程式碼中能註釋的地方都進行了註釋希望大家先跟著註釋打一遍,不要著急,當在黑色的星空中出現了結果,你就會為之振奮,有了繼續學下去的勇氣,當你對程式碼中的思想有了較深的理解後,再回

二叉搜尋樹的查詢、插入、刪除的與非實現C語言

【概念】 什麼是二叉搜尋樹? 二叉搜尋樹又稱二叉排序樹(按照中序遍歷,可以得到一組有序的序列),它或者是一顆空樹,或者是具有以下性質的二叉樹: 若他的左子樹不為空,則左子樹上所有節點的值都小於根結點的值。 若他的

第十二週—C語言 求解爬樓梯

/* 煙臺大學計算機學院 2016 作者:張威 完成日期:2016年11月18日 問題及描述:爬樓梯地方法種數,一次可以爬一階或兩階。 */ #include <stdio.h> #inc

漢諾塔呼叫C語言實現

1.遞迴演算法 遞迴演算法:是一種直接或者間接地呼叫自身的演算法。在計算機編寫程式中,遞迴演算法對解決一大類問題是十分有效的,它往往使演算法的描述簡潔而且易於理解。 遞迴過程一般通過函式或子過程來實現。 遞迴演算法的實質:是把問題轉化為規模縮小了的同類問題的子問題。然後

二分查詢和非實現c語言實現

#include<stdio.h>++ int seeqSearch(int a[],int n,int k){     int i=n-1;     for(;i>=0;i--){//遍歷陣列         if(a[i]==k){//找到對應的陣列

LeetCode 2.兩相加 Add Two Numbers C語言

題目描述: 給出兩個非空的連結串列用來表示兩個非負的整數。其中,它們各自的位數是按照逆序的方式儲存的,並且它們的每個節點只能儲存 一位 數字。 如果,我們將這兩個數相加起來,則會返回一個新的連結串列來表示它們的和。 您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。 示例

斐波拉契數列的和非寫法c/java

C語言版本:#include <stdio.h> long fib(long n) { if(n<=2) return(1); if(n>=3) return(fi

求解c語言以及python

/* ============================================================================ Name : sudoku.c Author : Joey Version

一箇中興的面試題,輸入兩個數n和m,從數列1,2,3……n中隨意取幾個數,使其和等於m,要求將其中所有組合列出來程式設計求解c語言函式分解法

原題目:輸入兩個數n和m,從數列1,2,3……n中隨意取幾個數,使其和等於m,要求將其中所有組合列出來程式設計求解 c語言解法分析:            先判定n和m的大小,如果m小於n,則只需從1,2……m之間找出和為m的組合即可,如果m大於n,則需要判斷1~n的和是否

徐鬆亮演算法教學-基於C語言(九宮格)求解含多解和解數統計

目錄 一,前言 電腦系統 編譯器 程式語言 流程 演示 一,前言 數獨,說實話我玩過,且並不是很喜歡玩,覺得無聊也太浪費時間,當然玩的水平也不咋樣。 但是我為什麼又寫這篇文章又編寫程式碼的去做呢? 因

—簡單方法C語言

迴文數即正反讀都是相同的數,如151、12321等,但不要忘了,個位數與0也是迴文數,雖然這不影響我們程式碼。 題目要求:輸入n組資料,每組資料判斷是否為迴文數,是的話輸出各位數和,不是輸出no; 既然正反都是相同,許多同學用了兩個陣列進行正反比對,但我認為我的方法更為簡易。程式碼如下。

Leetcode演算法題C語言11--有效的

題目:有效的數獨 判斷一個 9x9 的數獨是否有效。只需要根據以下規則,驗證已經填入的數字是否有效即可。 1 數字 1-9 在每一行只能出現一次。 2 數字 1-9 在每一列只能出現一次。 3 數

LeetCode 9. Palindrome NumberC語言

題目描述: 判斷一個整數是否是迴文數。迴文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。 示例 1: 輸入: 121 輸出: true 示例 2: 輸入: -121 輸出: false 解釋: 從左向右讀, 為 -121 。 從右向左

LeetCode 36. 有效的 Valid SudokuC語言

題目描述: 判斷一個 9x9 的數獨是否有效。只需要根據以下規則,驗證已經填入的數字是否有效即可。 數字 1-9 在每一行只能出現一次。 數字 1-9 在每一列只能出現一次。 數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。 上圖是一個部分填

先序、非層次建立二叉樹並用三序遍歷之C語言

 先序就是直接用遞迴的方法建立,層次使用了輔助陣列,後一種方法我覺得友好多了。 #include "stdio.h" #define MAXSIZE 50 #define TRUE 1 #define FALSE 0 typedef int boo

C語言整數劃分問題

對於一個正整數n的劃分,就是把n變成一系列正整數之和的表示式。注意,分劃與順序無關,例如6=5+1跟6=1+5是 同一種分劃。另外,單獨這個整數本身也算一種分劃。 例如:對於正整數n=5,可以劃分為: 1+1+1+1+1 1+1+1+2 1+1+3 1+2+2 2+3 1+4 5 輸入描述 輸入一個正整