八皇后问题

趣学算法 n皇后问题

#include<bits/stdc++.h>
using namespace std;
int n;//n表示n个皇后 
int x[105];//x[i]表示第i个皇后放置在第i行第x[i]列 
int countn;//countn表示n皇后问题可行解的个数 
bool check(int t){//约束函数:判断第t个皇后能否放在第i个位置 
	bool flag=true; 
	for(int j=1;j<t;++j){//判断该位置的皇后是否与前面t-1个已经放置的皇后冲突 
		if(x[t]==x[j]||t-j==fabs(x[t]-x[j])){//判断列、对角线是否冲突 
			flag=false;
			break;
		}
	}
	return flag; 
}
void dfs(int t){
	if(t>n){//如果当前位置为n,则表示已经找到了问题的一个解 
		countn++;
		for(int i=1;i<=n;++i)//打印路径 
			cout<<x[i]<<" ";
		cout<<endl;
		cout<<"----------"<<endl;
	}
	else
		for(int i=1;i<=n;++i){
			x[t]=i;
			if(check(t))
				dfs(t+1);
		}
}
int main(){
	cout<<"输入皇后个数n:";
	cin>>n;
	countn=0;
	dfs(1);
	cout<<"答案的个数是:"<<countn<<endl;
	return 0; 
}

洛谷 八皇后

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int n;
int x[15];
int cnt;
int cnt2;
bool check(int t){//判断第t个结点能否放在第i个位置 
    bool flag=1;
    for(int i=1;i<t;++i){//<t
        if(x[i]==x[t]||t-i==abs(x[i]-x[t])){
            flag=0;
            break;
        }
    }
    return flag;
}
void dfs(int t){
    if(t>n){
        ++cnt;
        if(cnt2<3){
            ++cnt2;
            for(int i=1;i<=n;++i)
                printf("%d ",x[i]); 
            printf("\n");
        }
    }else {
        for(int i=1;i<=n;++i){
            x[t]=i;//出现在这里 扩展结点? 
            if(check(t)) {
                dfs(t+1);
        }
    }
    }
}
int main(){
    scanf("%d",&n);
    dfs(1);
    printf("%d\n",cnt);
}

注意:最后一个测试点 n=13 TLE 代码首行手动开启O2优化可以过(真神奇呀)听说用bool标记数组不会超时,等我理解透彻再试

校oj 八皇后

#include<bits/stdc++.h>
using namespace std;
int n=8;
int cnt;
int x[10];
bool check(int t){
	bool flag=1;
	for(int i=0;i<t;++i){
		if(x[t]==x[i]||t-i==abs(x[t]-x[i])){
			flag=0;
			break;
		}
	} 
	return flag;
}
void dfs(int t){
	if(t==n){
		printf("No. %d\n",++cnt);
		for(int j=0;j<n;++j){//按输出要求转置
			for(int i=0;i<n;++i){
				if(j==x[i])printf("1 ");
				else printf("0 "); 
			}
			printf("\n");
		}
	}else{
		for(int i=0;i<n;++i){
			x[t]=i;
			if(check(t)){
				dfs(t+1);
			}
		}
	}
}

int main(){
	dfs(0);
}

注:

1.这是第一次从0开始回溯,以前都是从1开始

2.校oj输出顺序要求有点奇怪,通过观察,如果按前两题的板子,转置一下就对了(bright girl)

3.看了别人交的代码,用二维数组搜索,(也有转置的处理(输出book[ j ][ i ])),关键是,它回溯完以后还要清零,表示退回上一层的意思,搞得我有点晕,我的一维标记数组怎么没这种操作?还有他是先check,符合条件再标记,再往下搜,我是先扩展,符合条件再往下一层搜

它确实是要清零才可以呀,因为它是二维图搜索,这一行的这一列搜完,在以后的dfs里,或是因为找到解了,或是因为下面某行找不到满足条件的解,退回到这一层,那此行此列可不得清零吗,for循环继续搜索此行的下一列呀。我的一维数组x[i],记录的是第i行的列数,退回这层时,for循环判断此行下一列,直接x[t]=i了,所以不用清零呀。

行吧,在这自言自语的过程里,已经把那个迷雾重重的代码全弄懂了,贴在下面:

#include<bits/stdc++.h>
using namespace std;
const int n=9;
int book[n][n];
int tot;
bool check(int x,int y){
	for(int i=1;i<=x;++i){//判断[1,x]行 是否有与y同列的
		if(book[i][y]) return false;
		for(int j=1;j<=8;++j){
        //二重循环 判断值为1的book[i][j]是否与(正在判断的、即将扩展的)book[x][y]同对角线
			if(book[i][j]){
				if(x-i==abs(j-y))
					return false;
				else break;				
			}
		} 
	}
	return true;
}
void dfs(int step){
	if(step==n){
		++tot;
		cout<<"No. "<<tot<<endl;
		for(int i=1;i<=8;++i){
			for(int j=1;j<=8;++j){
				cout<<book[j][i]<<" ";
			}
			cout<<endl;
		}
		return;
	}
	for(int i=1;i<=8;++i){
		if(check(step,i)){
			book[step][i]=1;//符合条件的话标记为1
			dfs(step+1);
			book[step][i]=0;
		}
	}
	return;
}
int main(){
	dfs(1);
	return 0;
}

注:

1.dfs里的那个if,如果满足条件的话最终是要return,所以写不写else都可以

2.关于 满足条件再标记 和 先标记再看是否满足条件 的问题:二维数组解法,满足条件再标记,判断是否满足条件的时候,传过去的是要判断的坐标 (x,y),它只需要坐标,就能判断是否满足条件,而一维数组记录的是列数,必须要先赋值才能判断!我懂啦!(bright girl~)

我发现碎碎念型博客对我思考问题很有帮助(虽然不太好看,但我写爽了就够了2333),帮我条分缕析,直面问题的症结,光用脑袋想的话,我常常忽视这些疑点,囫囵吞枣就过去了,其实自己也知道不是太懂,但没法深入思考——写下来就很好!

八皇后,就到这!

继续做其他回溯的题目!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值