POJ-1321.棋盘问题.(回溯)
做完题之后看了网上的一些题解但是发现他们的解释大部分都是错误的,所以就自己写了一下,笔者能力也有限,有错误之处大家多多指正。
第一次看题的时候以为就是简单的八皇后,但是写了之后发现存在很多问题,比如需要记录放入的棋子数,在一次访问之后没有回复原来棋盘的形状等一些问题。
本题思路:
回溯思想,对于每一行,从这一行的第一个开始放棋子,如果发现棋子可以放就放下一个棋子并且将已经放了棋子的数目更新,如果某一次放的棋子数目已经达到题目要求个数,则回溯到这一行的其它列并回复原来的状态继续放棋子,直到所有情况都放完为止,这里需要特别注意的是每次放棋子要改变对应列的状态和放的棋子个数,但是当回溯到这个对其它列进行操作的时候需要将这两个状态都更新为上一个状态即放这个棋子之前的状态,最后记得需要多后面的每行进行统计,因为棋子可能不是从第一行开始放的。
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 5 const int maxn = 8; 6 int n, k, ans, count; 7 char maze[maxn][maxn]; 8 bool isvisited[maxn];//表示某一列是否被访问 9 10 void dfs(int u) { 11 if(count == k) { 12 ans ++; 13 return; 14 } 15 if(u >= n) return; 16 for(int v = 0; v < n; v ++) { 17 if(maze[u][v] == '#' && !isvisited[v]) { 18 count ++;//更新放了这个棋子之后的状态 19 isvisited[v] = true; 20 dfs(u + 1); 21 count --;//更新到放这个棋子之前的状态 22 isvisited[v] = false; 23 } 24 } 25 dfs(u + 1);//棋子的起始行可能不是第一行 26 } 27 28 int main () { 29 while(~scanf("%d %d", &n, &k)) { 30 if(n == -1 && k == -1) break; 31 memset(isvisited, false, sizeof(isvisited)); 32 ans = count = 0; 33 getchar(); 34 for(int i = 0; i < n; i ++) { 35 for(int j = 0; j < n; j ++) { 36 maze[i][j] = getchar(); 37 } 38 getchar(); 39 } 40 dfs(0); 41 printf("%d\n", ans); 42 } 43 return 0; 44 }
时间并不会因为你的迷茫和迟疑而停留,就在你看这篇文章的同时,不知道有多少人在冥思苦想,在为算法废寝忘食,不知道有多少人在狂热地拍着代码,不知道又有多少提交一遍又一遍地刷新着OJ的status页面……
没有谁生来就是神牛,而千里之行,始于足下!