zoukankan      html  css  js  c++  java
  • 双倍快乐:两个八皇后:ybt1213&ybt1214

    ybt1213 八皇后 & ybt1214 八皇后

    ybt1213

    【题目描述】

    在国际象棋棋盘上放置八个皇后,要求每两个皇后之间不能直接吃掉对方。

    【无输入】

    【输出】

    按给定顺序和格式输出所有八皇后问题的解(见样例)。
    【输出样例】

    No. 1
    1 0 0 0 0 0 0 0 
    0 0 0 0 0 0 1 0 
    0 0 0 0 1 0 0 0 
    0 0 0 0 0 0 0 1 
    0 1 0 0 0 0 0 0 
    0 0 0 1 0 0 0 0
    0 0 0 0 0 1 0 0 
    0 0 1 0 0 0 0 0 
    No. 2
    1 0 0 0 0 0 0 0
    0 0 0 0 0 0 1 0
    0 0 0 1 0 0 0 0
    0 0 0 0 0 1 0 0
    0 0 0 0 0 0 0 1
    0 1 0 0 0 0 0 0
    0 0 0 0 1 0 0 0
    0 0 1 0 0 0 0 0
    ...以下省略
    

    【题解】

    每个皇后可以吃掉所在行,列,斜线共八个方向的棋子,国际象棋棋盘共有八行八列,有2*15个斜线因此八皇后问题的策略就是在每一行,每一列,有且只有一个皇后,并且任意两个皇后不在同一斜线。

    观察样例,不难发现是以每一列皇后的所在行数升序排列的,(参考ybt1214,不过与其相反,ybt1214是以每一行的列数升序排列的)所以就可以这样分类讨论。

    这时就可以确定方向,从左往右一列一列的枚举,在每一列分别枚举不同可行的皇后位置,每当假设一个位置有皇后,那就将她右边的控制点(控制点是什么?可以参考过河卒)打上标记,并且随着皇后的变化不断更新,这样就可以使以后的皇后有正确的可行位置。

    这就是思路,算法还是要在代码中体现。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int num=0;
    bool a[30][30]={0},b[30][30]={0};//a是方案棋盘,也就是存皇后的位置;b是控制棋盘,存当前能放或不能放皇后的位置
    void print() {//打印方案,不用多说
    	printf("No. %d
    ",++num);//别忘了空格
    	for(int i=1;i<=8;i++) { 
    		for(int j=1;j<=8;j++)
    			printf("%d ",int(a[i+10][j+10]));//加10的原因在后面第28行
    		printf("
    ");
    	}
    	return;
    }
    void dfs(int x,int y) {//x是当前已经决定的皇后的所在行,y是当前已经决定的皇后的所在列 
    	a[x+10][y+10]=1;//首先使方案中本格有皇后
    	if(y==8) {//列数到了最右边
    		print();//可以输出
    		a[x+10][y+10]=0;//由于已经输出方案,所以需要继续搜索,此皇后位置要空出来
    		return; 
    	}
    	bool z[30][30]={0};//这是对控制棋盘起备份作用的备份棋盘,用于之后还原操作
    	for(int k=1;y+k<=8;k++) {
    		z[x+10][y+k+10]=b[x+10][y+k+10];//备份
    		z[x+k+10][y+k+10]=b[x+k+10][y+k+10];
    		z[x-k+10][y+k+10]=b[x-k+10][y+k+10];
    		b[x+10][y+k+10]=1;//控制她右边可控制的格子
    		b[x+k+10][y+k+10]=1;//由于这里+k以及下面-k,所以数组可能超限(10*10),所以把数组改为(30*30),并将元素都向后移10位避免超限,这就是所有下标都加10的原因
    		b[x-k+10][y+k+10]=1;
    	}
    	for(int k=1;k<=8;k++) {//开始枚举
    		if(!(b[k+10][y+11])) {//格子未被控制
    			dfs(k,y+1);//在(k,y+1)放置皇后
    		}
    	}
    	for(int k=1;y+k<=8;k++) {//还原
    		b[x+10][y+k+10]=z[x+10][y+k+10];
    		b[x+k+10][y+k+10]=z[x+k+10][y+k+10];
    		b[x-k+10][y+k+10]=z[x-k+10][y+k+10];
    	}
    	a[x+10][y+10]=0;//和19行类似,再把这个皇后拿走
    	return;
    }
    int main() {
    	for(int l=1;l<=8;l++)
    		dfs(l,1);//枚举第一个皇后的位置
    	return 0; 
    }
    

    做这道题时,我遇到几个问题:

    1.玄学的t变量

    在一开始,本来想打个标记,判断无解跳出,在现在的第30行的后面建了一个t变量。最后,程序调好了,t也没用了,但是当我删掉t了以后,程序无输出,调试发现根本没有执行17行的if语句。然后又加上t,还是不行。吓得我赶紧撤销,撤回t还在的情况,唯一的区别是之前的t有赋值0。当t有赋值时,程序正常输出,无论赋值多少。

    最后只能带着t提交,结果re,发现是爆数组了,因为皇后的斜着走操作有可能爆10*10的数组,最后数组扩大才解决。

    2.格式出错

    终于调好了程序的我再次提交,结果格式错误,仔细查看样例发现“No.”里的“.”后面是有空格的,又贡献了一次的KD

    ybt1214

    【题目描述】

    会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 × 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。

    对于某个满足要求的8皇后的摆放方法,定义一个皇后串a与之对应,即a=b1b2...b8a=b1b2...b8,其中bi为相应摆法中第i行皇后所处的列数。已经知道8皇后问题一共有92组解(即92个不同的皇后串)。

    给出一个数b,要求输出第b个串。串的比较是这样的:皇后串x置于皇后串y之前,当且仅当将x视为整数时比y小。

    【输入】

    第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数b(1≤b≤92)。

    【输出】

    输出有n行,每行输出对应一个输入。输出应是一个正整数,是对应于b的皇后串。

    【输入样例】

    2 1 92
    

    【输出样例】

    15863724
    84136275
    

    【题解】

    在上一题的基础上把打印方案改为存储方案即可

    注意!由于方案的对称性,所以虽然优先级不同,但还是可以通用之前的方案顺序。(务必先看ybt1213)

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int num=0,c,n,ans[100][30];
    bool a[30][30]={0},b[30][30]={0};
    void record() {
    	++num;
    	for(int i=1;i<=8;i++) { 
    		for(int j=1;j<=8;j++)
    			if(a[i+10][j+10])
    				ans[num][j+10]=i;
    	}
    	return;
    }
    void dfs(int x,int y) {
    	a[x+10][y+10]=1;
    	if(y==8) { 
    		record();
    		a[x+10][y+10]=0;
    		return; 
    	}
    	bool z[30][30]={0};
    	for(int k=1;y+k<=8;k++) {
    		z[x+10][y+k+10]=b[x+10][y+k+10];
    		z[x+k+10][y+k+10]=b[x+k+10][y+k+10];
    		z[x-k+10][y+k+10]=b[x-k+10][y+k+10];
    		b[x+10][y+k+10]=1;
    		b[x+k+10][y+k+10]=1;
    		b[x-k+10][y+k+10]=1;
    	}
    	for(int k=1;k<=8;k++) {
    		if(!(b[k+10][y+11])) {
    			dfs(k,y+1);
    		}
    	}
    	for(int k=1;y+k<=8;k++) {
    		b[x+10][y+k+10]=z[x+10][y+k+10];
    		b[x+k+10][y+k+10]=z[x+k+10][y+k+10];
    		b[x-k+10][y+k+10]=z[x-k+10][y+k+10];
    	}
    	a[x+10][y+10]=0;
    	return;
    }
    int main() {
    	cin>>n;
    	for(int l=1;l<=8;l++)
    		dfs(l,1);
    	for(int m=1;m<=n;m++) {
    		cin>>c;
    		for(int o=1;o<=8;o++)
    			cout<<ans[c][o+10];
    		cout<<endl; 
    	}
    	return 0; 
    }
    
  • 相关阅读:
    进程池,线程池,协程,gevent模块,协程实现单线程服务端与多线程客户端通信,IO模型
    线程相关 GIL queue event 死锁与递归锁 信号量l
    生产者消费者模型 线程相关
    进程的开启方式 进程的join方法 进程间的内存隔离 其他相关方法 守护进程 互斥锁
    udp协议 及相关 利用tcp上传文件 socketserver服务
    socket套接字 tcp协议下的粘包处理
    常用模块的完善 random shutil shevle 三流 logging
    day 29 元类
    Django入门
    MySQL多表查询
  • 原文地址:https://www.cnblogs.com/Wild-Donkey/p/12238957.html
Copyright © 2011-2022 走看看