1. 程式人生 > >POJ1321-Chess Problem

POJ1321-Chess Problem

全解題報告索引目錄 -> 【北大ACM – POJ試題分類

-------------------------------------------------------------------------

大致題意:

中文題。。我沒什麼好說的

解題思路:

DFS,沒想法就很難很難,有想法就很容易的題

棋盤規則與否不是難點,無論規則不規則都可以用標記去解決

難點在於 棋盤的行數(列數)n 與 待擺放的棋子總數k  的關係為k<=n

K==n時還是比較好辦的

K<n時就讓人有點迷糊不知怎樣處理了

網上普遍做法都是 逐行深搜,效率不錯,我也稍微借鑑了,具體看程式,不多說了,搜尋的題抽象性太強,文字很難說清楚

//Memory Time 
//184K   32MS 

#include<iostream>
using namespace std;

bool chess[9][9];
bool vist_col[9];  //列標記
int status;  //狀態計數器
int n,k;

void DFS(int row,int num)  //逐行搜尋,row為當前搜尋行,num為已填充的棋子數
{
	if(num==k)
	{
		status++;
		return;
	}

	if(row>n)    //配合下面DFS(row+1,num); 語句使用,避免搜尋越界
		return;

	for(int j=1;j<=n;j++)
		if(chess[row][j] && !vist_col[j])
		{
			vist_col[j]=true;  //放置棋子的列標記
			DFS(row+1,num+1);
			vist_col[j]=false; //回溯後,說明擺好棋子的狀態已記錄,當前的列標記還原
		}

	DFS(row+1,num);   //這裡是難點,當k<n時,row在等於n之前就可能已經把全部棋子放好
	                  //又由於當全部棋子都放好後的某個棋盤狀態已經在前面迴圈時記錄了
	                  //因此為了處理多餘行,令當前位置先不放棋子,搜尋在下一行放棋子的情況
	return;
}

int main(int i,int j)
{
	while(cin>>n>>k)
	{
		if(n==-1 && k==-1)
			break;

		/*Initial*/

		memset(chess,false,sizeof(chess));
		memset(vist_col,false,sizeof(vist_col));
		status=0;

		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
			{
				char temp;
				cin>>temp;
				if(temp=='#')
					chess[i][j]=true;
			}

		DFS(1,0);  //注意初始化的值別弄錯了
		cout<<status<<endl;
	}
	return 0;
}