ページ 11

数独を解くアルゴリズム

Posted: 2015年5月02日(土) 18:16
by よっぴー
はじめまして。初投稿です。
ひょんなことから、「数独を解くプログラム」を作ることになり、
以下のC/C++(開発の関係上C++だが、ほとんどC言語のつもりで書きました)プログラムを書いてみました。
ですが、実行してみると途中で動作が止まってしまいます。
何度も見直してみましたが、とても一人では見つけられそうにないのでこちらに質問させていただきました。
なぜ、止まってしまうのか、コードのどこが原因なのか教えていただきたいです。
また、そもそも数独を解くプログラムとして機能できているのかも教えて欲しいです。

コード:

#include "stdafx.h"
#include "stdio.h"
#include <time.h>
#include <iostream>
using namespace std;
#define Size 9
 
int ban[Size][Size], randoms[Size];
 
//ここにresetBan(),Show(),Input()があります(問題あるとは考えられないので省略)

void makeRandomNumbers(){//1~9の値をランダムな順に格納
	srand((unsigned int)time(NULL));//乱数初期値の初期化
	for (int i = 0; i < Size; i++)
		randoms[i] = i + 1;
	for (int j = 0; j < Size; j++){
		int k = rand() % 9;
		int temp = randoms[j];
		randoms[j] = randoms[k];
		randoms[k] = temp;
	}
}
 
bool checkLinCol(int Column, int Line, int value) {//行・列の重複を調べる
	for (int i = 0; i < Size; i++) {
		// 同じマスは調べない。
		if (i != Column)
			if (ban[Line][i] == value)
				return true;
		if (i != Line)
			if (ban[i][Column] == value)
				return true;
	}
	return false;
}
 
bool checkBox(int Column, int Line, int value) {
	// マスにおける3x3ブロックの一番左上を計算。
	int startLine = Line / 3 * 3;
	int startColumn = Column / 3 * 3;
	// 3x3ブロックの中のこのマス以外を調べる。
	for (int i = startLine; i < startLine + 3; i++){
		for (int j = startColumn; j < startColumn + 3; j++) {
			if (!(i == Line && j == Column)) {
				if (ban[i][j] == value)
					return true;
			}
		}
	}
	return false;
}
 
bool solve(int Column, int Line) {
	// 最終地点まで来た
	if (Line == Size)
		return true;
	// 空白でない
	if (ban[Line][Column] != 0) {
		// 次のマスに進む。
		if (solve(Column == 8 ? (Line + 1) : Line, (Column + 1) % 9))
			return true;
	}
	else {//空白である(まだ埋めていない)
		makeRandomNumbers();
		for (int i = 0; i < Size; i++) {
			// この行・列・3x3ブロックにこの数字が重複しない
			if (!checkLinCol(Column, Line, randoms[i]) && !checkBox(Column, Line, randoms[i])) {
				ban[Line][Column] = randoms[i];
 
				// 次のマスに進む。
				if (solve(Column == 8 ? (Line + 1) : Line, (Column + 1) % 9))
					return true;
				else
					ban[Line][Column] = 0;
			}
		}
	}
	return false;
}
 
int _tmain(int argc, const char * argv[]) {

	resetBan();
 
	Input();
 
	solve(0,0);//この関数に問題があると考えられる
 
	Show();
	
	return 0;
}

Re: 数独を解くアルゴリズム

Posted: 2015年5月02日(土) 20:50
by みけCAT
適当な実装で補ってコンパイル、実行してみました。

stdafx.h

コード:

#ifndef STDAFX_H_GUARD_09CB4F71_A3A2_4EA0_8CE1_0C5689E5FDD3
#define STDAFX_H_GUARD_09CB4F71_A3A2_4EA0_8CE1_0C5689E5FDD3

#include <cstdlib>

extern int ban[9][9];
int _tmain(int argc, const char * argv[]);

void resetBan();
void Show();
void Input();

#endif
hokan.cpp

コード:

#include <cstdio>
#include "stdafx.h"

void resetBan() {
	for(int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) ban[i][j] = 0;
	}
}

void Show() {
	for(int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) printf("%d%c", ban[i][j], j + 1 < 9 ? ' ' : '\n');
	}
}

void Input() {
	for(int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) {
			if (scanf("%d", &ban[i][j]) != 1) {
				fputs("Input error!!!\n", stderr);
				exit(1);
			}
		}
	}
}

int main(void) {
	const char *dummy[1] = {NULL};
	return _tmain(0, dummy);
}
solveの引数と呼び出す時でColumnとLineの位置が逆であるため、Line == Sizeが成立せず、無限再帰になっているようです。

Re: 数独を解くアルゴリズム

Posted: 2015年5月02日(土) 21:12
by よっぴー
無事解決しました。本当にありがとうございました。
一人ではこんなに早く解決しませんでした。回答ありがとうございました。
今年一年、お世話になることがあると思いますので、今後ともよろしくお願いします。