用NXT做的數獨機器人
前面比較繁瑣的工作是判斷位置
以及掃描出數字
將9*9表格讀入機器後就可以開始進行運算
將9*9表格讀入機器後就可以開始進行運算
藉此機會
就來研究看看解數獨的程式該如何寫吧
首先要瞭解規則
在1~9行內絕對只有1~9的數字 且不重複
在1~9列內絕對只有1~9的數字 且不重複
以每9格(正方) 為單位 9格內也只有1~9的數字 且不重複
例如:
1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
2 3 4 5 6 7 8 9 1
5 6 7 8 9 1 2 3 4
8 9 1 2 3 4 5 6 7
3 4 5 6 7 8 9 1 2
這就算是一個數獨的答案
然而數獨的每個題目 永遠都只會有一個答案(如果有很多答案就沒什麼好玩了)
第一種解法:
利用佇列解
我是參考書上寫的
不過這方法似乎只能解基本的數獨
因為他是將未填入數字的位置 存入佇列中
再一一拿出來做
因為有一些數獨是需要用判斷的才能解
所以這種解法可能無法適用於所有的題目
#include <stdio.h> struct data_item{ int x,y,val; }; struct sudoku_item{ int x,y; int num; int val[10]; int resVal; }; sudoku_item sudoku[9][9]; int rear,front; data_item *dataQ[9*9]; void createQueue(){ rear = front = 0; } void enque(data_item *dataItem){ dataQ[rear] = dataItem; rear = (rear +1) % (9*9); } data_item *deque(){ data_item *dataItem = dataQ[front]; front = (front + 1)% (9*9); return dataItem; } int isEmpty(){ return rear == front; } data_item *clrSudokuItem(int x, int y, int n){ data_item *dataItem; int i; if(sudoku[x][y].resVal == 0){ sudoku[x][y].num-= sudoku[x][y].val[n]; sudoku[x][y].val[n] = 0; if(sudoku[x][y].num == 1) for(i = 1; i < 10; i++) if(sudoku[x][y].val[i] == 1){ sudoku[x][y].resVal = i; dataItem = (data_item *) new data_item; dataItem ->x = x; dataItem ->y = y; dataItem ->val = i; return dataItem; } } return NULL; } void preprocess(int dataArr[][9]){ data_item *dataItem; int i,j,k; createQueue(); for(i = 0; i < 9;i++){ for(j = 0; j< 9; j++){ printf("%d ",dataArr[i][j]); if(dataArr[i][j] != 0){ sudoku[i][j].num = 1; sudoku[i][j].resVal = dataArr[i][j]; dataItem = (data_item *) new data_item; dataItem->x = i; dataItem->y = j; dataItem->val = dataArr[i][j]; enque(dataItem); }else{ sudoku[i][j].x = i; sudoku[i][j].y = i; for(k = 1; k<10; k++) sudoku[i][j].val[k] = 1; sudoku[i][j].num = 9; sudoku[i][j].resVal = 0; } } printf("\n"); } } void processSudoku(){ data_item *dataItem,*retData; int i,j; while(!isEmpty()){ int x,y,val; dataItem = deque(); x =dataItem->x; y =dataItem->y; val = dataItem->val; for(i = 0; i<9; i++){ if(i != y){ retData = clrSudokuItem(x,i,val); if(retData != NULL) enque(retData); } if(i != x){ retData = clrSudokuItem(i,y,val); if(retData != NULL) enque(retData); } } for(i = 0; i<3; i++) for(j = 0; j<3; j++){ int m = x/3 *3 +i; int n = y/3 *3 +j; if(m!=x && n != y){ retData = clrSudokuItem(m,n,val); if(retData != NULL) enque(retData); } } } } void output(){ int i,j; printf("Answer:\n"); for(i = 0; i<9; i++){ for(j = 0; j<9; j++) printf("%d ",sudoku[i][j].resVal); printf("\n"); } } int main(){ int data[9][9] = { {3,0,1,0,0,9,0,5,0}, {0,9,0,0,0,4,1,8,0}, {0,0,0,6,2,0,9,0,4}, {1,0,0,0,4,0,0,6,0}, {0,5,0,0,6,0,0,4,0}, {0,8,0,9,7,0,5,0,2}, {0,0,5,0,3,2,0,0,0}, {0,2,9,0,0,0,0,0,5}, {0,6,0,5,9,0,4,0,0}}; preprocess(data); processSudoku(); output(); getchar(); return 0; }
第二種解法:
第二次我是利用遞迴讓所有可能性直接跑完(直到有答案)
相信大家都知道遞迴的缺點 浪費時間,空間
不過我還沒想到可以縮短執行時間,空間的方法
若有 歡迎指教
#include "stdafx.h" struct local_mark{ int x[9]; int y[9]; int z[9]; }; struct point{ int x; int y; }; local_mark *Number_Place_set(int [][9]); bool Number_Place_game(int [][9], local_mark *); int local_val(int, int); int bitcount(int ); void print_data(int [][9]); int main(){ int data[9][9] = { {3,0,1,0,0,9,0,5,0}, {0,9,0,0,0,4,1,8,0}, {0,0,0,6,2,0,9,0,4}, {1,0,0,0,4,0,0,6,0}, {0,5,0,0,6,0,0,4,0}, {0,8,0,9,7,0,5,0,2}, {0,0,5,0,3,2,0,0,0}, {0,2,9,0,0,0,0,0,5}, {0,6,0,5,9,0,4,0,0}}; printf("Subject:\n"); print_data(data); local_mark *mark = Number_Place_set(data); printf("Answer:\n"); if(Number_Place_game(data,mark)){ print_data(data); }else{ printf("No solution!\n"); } getchar(); return 0; } local_mark *Number_Place_set(int data[][9]){ local_mark *mark = (local_mark*) new local_mark; for(int i = 0; i < 9; i++ ) mark -> x[i] = mark -> y[i] = mark -> z[i] = 0; for(int i = 0; i < 9; i++ ) for(int j = 0; j < 9; j++) if(data[i][j]){ mark -> x[j] |= (1 << data[i][j]-1); mark -> y[i] |= (1 << data[i][j]-1); mark -> z[local_val(i,j)] |= (1 << data[i][j]-1); } return mark; } bool Number_Place_game(int data[][9], local_mark *mark){ point *p = (point*) new point; int m , max = 0 , count = 0; for(int i = 0; i < 9; i++ ) for(int j = 0; j < 9; j++) if(!data[i][j]){ count++; m = mark->x[j] | mark->y[i] | mark->z[local_val(i,j)]; if(bitcount(m) > bitcount(max)){ max = m; p -> x = j; p -> y = i; } } if(count == 0) return true; for(int i = 0; i < 9; i++) if(max != (max | (1 << i))){ data[ p->y ][ p->x ] = i+1; mark -> x[ p->x ] |= (1 << i); mark -> y[ p->y ] |= (1 << i); mark -> z[ local_val( p->y , p->x ) ] |= (1 << i); if(Number_Place_game(data,mark)){ return true; }else{ data[ p->y ][ p->x ] = 0; mark -> x[ p->x ] &= ~(1 << i); mark -> y[ p->y ] &= ~(1 << i); mark -> z[ local_val( p->y , p->x ) ] &= ~(1 << i); } } return false; } int local_val(int x,int y){ return y/3+(x/3)*3; } int bitcount(int x){ int b; for(b = 0; x; x &= x-1) ++b; return b; } void print_data(int data[][9]){ for(int i = 0; i < 9; i++){ for(int j = 0; j < 9; j++) printf("%d ",data[i][j]); printf("\n"); } }
0 留言:
張貼留言