POJ1321 搜索之回溯法

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

主要思路是依次遍历每一个格子,首先看是不是空(#),如果是且与之前的棋子不冲突的话就放一个棋子在这里,记录该棋子所在行号和列号。之后再去寻找下一个能放棋子的位置,直到所有棋子放完可行解数量即+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++){//回溯时行号为上一个棋子的行号+1
			for (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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值