1. 程式人生 > >一步一步寫演算法(之八皇后)

一步一步寫演算法(之八皇后)

【 宣告:版權所有,歡迎轉載,請勿用於商業用途。  聯絡信箱:feixiaoxing @163.com】

    八皇后是一道很具典型性的題目。它的基本要求是這樣的:在一個8*8的矩陣上面放置8個物體,一個矩陣點只允許放置一個物體,任意兩個點不能在一行上,也不能在一列上,不能在一條左斜線上,當然也不能在一條右斜線上。

    初看到這道題目,大家的第一印象是遍歷,但是經過實踐之後發現遍歷其實不好寫,而且複雜度很低。不僅需要遍歷8*8*8*8*8*8*8*8*8 = 2^24次資料,還要判斷各種條件,實際的計算複雜度還要比較這個高。其實我們仔細看一看,這中間很多的計算其實很多是不需要的,因為如果我們在某一行沒有可以插入的資料的話,那麼這後面的行其實就不用考慮了。也就是說,我們只有在保證前面 插入的物體都合法有效的情況下,才能進行下一次的物體插入。無謂的遍歷只會是無用功。

   那麼,我們應該怎麼做呢?其實步驟不太難:

    (1)在第n行尋找可以插入的位置,中間涉及到位置合法性的判斷

    (2)如果沒有可以插入的位置,返回

    (3)如果有可以插入的位置, 插入資料。此時再判斷是否已經是最後一行,如果是,列印輸出返回;反之繼續對下一行資料進行試探處理。

    有了上面的步驟,我們就可以書寫程式碼了。老規矩,朋友們可以自己先嚐試一下。

    a)定義全域性堆疊和列印函式

static int gEightQueen[8] = {0};
static int gCount = 0;

void print()
{
	int outer;
	int inner;

	for(outer = 0; outer <8; outer ++){
		for(inner = 0; inner < gEightQueen[outer]; inner ++)
			printf("* ");

		printf("# ");

		for(inner = gEightQueen[outer] + 1; inner < 8; inner ++)
			printf("* ");

		printf("\n");
	}

	printf("=====================================\n");
}
    b)新增位置合法性的函式判斷
int check_pos_valid(int loop, int value)
{
	int index;
	int data;

	for(index = 0; index < loop; index ++){
		data = gEightQueen[index];

		if(value == data)
			return 0;

		if((index + data) == (loop + value))
			return 0;

		if((index - data) == (loop - value))
			return 0;
	}

	return 1;
}
    c) 八皇后遍歷
void eight_queen(int index)
{
	int loop;

	for(loop = 0; loop < 8; loop++){
		if(check_pos_valid(index, loop)){
			gEightQueen[index] = loop;

			if(7 == index){
				gCount ++, print();
			    gEightQueen[index] = 0;
				return;
			}
			
			eight_queen(index + 1);
			gEightQueen[index] = 0;
		}
	}
}

總結:

    (1)迭代遞迴是程式設計的難點,需要自己好好實踐,看別人寫一百遍,不如自己寫一遍

    (2)遞迴的時候務必注意函式return的出口

    (3)遞迴函式中語句的順序不要隨意更換

    (4)遞迴函式中注意資料的儲存和恢復

    (5)遞迴函式也要驗證,可以用程式驗證法,也可以用其他函式的結果來驗證


ps:

    下面是完整的程式碼,大家可以直接儲存成queue.cpp,直接編譯執行即可。可以打印出所有92種情況,

#include <iostream>
using namespace std;

static int gEightQueen[8] = {0};
static int gCount = 0;


void print()
{
	int outer;
	int inner;

	for(outer = 0; outer <8; outer ++){
		for(inner = 0; inner < gEightQueen[outer]; inner ++)
			printf("* ");

		printf("# ");

		for(inner = gEightQueen[outer] + 1; inner < 8; inner ++)
			printf("* ");

		printf("\n");
	}

	printf("=====================================\n");
}

int check_pos_valid(int loop, int value)
{
	int index;
	int data;

	for(index = 0; index < loop; index ++){
		data = gEightQueen[index];

		if(value == data)
			return 0;

		if((index + data) == (loop + value))
			return 0;

		if((index - data) == (loop - value))
			return 0;
	}

	return 1;
}



void eight_queen(int index)
{
	int loop;

	for(loop = 0; loop < 8; loop++){
		if(check_pos_valid(index, loop)){
			gEightQueen[index] = loop;

			if(7 == index){
				gCount ++, print();
			    gEightQueen[index] = 0;
				return;
			}
			
			eight_queen(index + 1);
			gEightQueen[index] = 0;
		}
	}
}



int main(int argc, char* argv[])
{
	eight_queen(0);
	printf("total = %d\n", gCount);
	return 1;
}