双倍快乐:两个八皇后:ybt1213&ybt1214

删除回忆录丶 提交于 2020-01-28 21:44:07

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\n",++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("\n");
    }
    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; 
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!