POJ1321 搜索之回溯法

来源:互联网 发布:php crypt 编辑:程序博客网 时间:2024/05/16 07:24

因为看《算法竞赛入门经典》看到了讲回溯这一章节,就拿了一个搜索题来练练手。这个题用回溯做还比较简单。

主要思路是依次遍历每一个格子,首先看是不是空(#),如果是且与之前的棋子不冲突的话就放一个棋子在这里,记录该棋子所在行号和列号。之后再去寻找下一个能放棋子的位置,直到所有棋子放完可行解数量即+1;遇到没有可放的情况则返回上一层调用(这就是“回溯”)。第一次提交是LTE,分析原因错误出现在我的思路上。我想的是把每个棋子看成不同的,这样求解出答案后再除以所有棋子全排列的情况。以题目给的测试用例说明就是:

4 4...#..#..#..#...
在这种情况下答案是1,而不是24,也就是说棋子都是一样的。而我一开始是按照棋子不一样去做,得出结果是24后再除以4!,即24/4!=1。虽然结果正确但由于搜索了太多没用的情况所以超时了。其实要想不重复也很简单,只需要在寻找下一个棋子时让行号从上一个棋子的行号+1开始即可做到不重复。另外在回溯的时候要特别注意修改了的全局变量要及时复原!这是非常容易错的一点!!!!切记!!!!!

下面为代码:

#include<iostream>using namespace std;char board[8][8];int visit[8][2];//visit[i][0]记录第i个棋子的行号visit[i][1]记录列号int count;void search(int cur,int k,int n){if(cur==k) count++;else{for (int i=cur?visit[cur-1][0]+1:0;i<n;i++){//回溯时行号为上一个棋子的行号+1for (int j=0;j<n;j++){//如果cur是0,则行号从0开始if (board[i][j]=='.') continue;int ok=1;for (int p=0;p<cur;p++){if (visit[p][0]==i||visit[p][1]==j){//检查是否会与前cur个值发生冲突ok=0;break;}}if(ok==1){visit[cur][0]=i;visit[cur][1]=j;search(cur+1,k,n);visit[cur][0]=0;//切记!!!!!!!visit[cur][1]=0;//将修改过的全局变量修改回来!}}}}}int main(){int n,k;while(cin>>n>>k&&n!=-1){count=0;memset(board,' ',sizeof(board));memset(visit,0,sizeof(visit));for (int i=0;i<n;i++){cin>>board[i];}search(0,k,n);cout<<count<<endl;}return 0;}


原创粉丝点击