软考考点之下午题,2019上半年算法及程序设计 N皇后问题

一直以来,觉得软考最实用的部分,就是算法及java或c++程序设计部分了,也是自己需要长期掌握的,从今天开始正式复习此部分。

做题时一定要结合上下文进行作答,要相信,正确答案一定是最简单的。

主要是自己还没写过的算法及概念的复习还有就是java或c++的语法。 

如2019年上半年下午题第4题。

第4题:阅读下列说明和C代码,回答问题1至问题3,将解答写在答题纸的对应栏内。
【说明】
n皇后问题描述为:在一个n×n的棋盘上摆放n个皇后,要求任意两个皇后不能冲突,即任意
两个皇后不在同一行、同一列或者同一斜线上。
算法的基本思想如下:
将第i个皇后摆放在第i行,i从1开始,每个皇后都从第1列开始尝试。尝试时判断在该列摆放
皇后是否与前面的皇后有冲突,如果没有冲突,则在该列摆放皇后,并考虑摆放下一个皇
后;如果有冲突,则考虑下一列。如果该行没有合适的位置,回溯到上一个皇后,考虑在原
来位置的下一个位置上继续尝试摆放皇后,......,直到找到所有合理摆放方案。

【C代码】
下面是算法的C语言实现。
(1)常量和变量说明
n: 皇后数,棋盘规模为n×n
queen[]: 皇后的摆放位置数组, queen[i]表示第i个皇后的位置, 1≤queen[i]≤n
(2)C程序

#include <stdio.h>
#define n 4
int queen[n+1];

void Show(){ /* 输出所有皇后摆放方案 */
int i;
printf("(");
for(i=1;i<=n;i++){
printf(" %d",queen[i]);
}
printf(") ");
}
int Place(int j){ /* 检查当前列能否放置皇后,不能放返回0,能放返回1 */
int i;
for(i=1;i<j;i++){ /* 检查与已摆放的皇后是否在同一列或者同一斜线上 */
if( (1) ) ‖ abs(queen[i]-queen[j]) == (j-i)) {
return 0;
}
}
return (2) ;
}
void Nqueen(int j){
int i;
for(i=1;i<=n;i++){
queen[j] = i;
if( (3) ){
if(j == n) { /* 如果所有皇后都摆放好,则输出当前摆放方案 */
Show();
} else { /* 否则继续摆放下一个皇后 */
(4) ;
}
}
}
}
int main(){
Nqueen (1);
return 0;
}
问题:4.1【问题1】(8分)
根据题干说明,填充C代码中的空(1)〜(4)。问题:4.2【问题2】(3分)
根据题干说明和C代码,算法采用的设计策略为 (5)。问题:4.3【问题3】(4分)
当n=4时,有 (6) 种摆放方式,分别为 (7)

答:像这种算法填空的题,难度还是不小的,如何作答?

明白算法的思想后,就是看代码实现了,一定要搞明白每个变量及数组,也就是先明白抽象出来的数据结构,这点与我们平时写算法时的思路是一样的。并结合算法思想,如何用给的这些变量来实现算法?

这题是第一次见代码,所以一头雾水。

第一空,可以根据提示,不能放返回0,能放返回1  ,if()里放的是return 0,不能放的情况,该填什么呢?可以看到后面是斜线的情况,那么就应该填在同一行上的情况  。应该填 queen[i]==queen[j];

第二空 ,很简单,能放的话是  返回1

第三空:不好填,先看第四空,提示是继续摆放下一个皇后,所以应该填本函数的递归调用Nqueen(j+1)

若之前没接触过N皇后问题,估计很难答对,正确的是Place(j)&&j<n

 

 

 

n皇后问题:

约束条件:除了不能在同一行,同一列外,还不能在同一斜线

 

其实并不需要一个n*n的数组,我们只需要一个n长度的数组来存位置。

表示方式: arr[i] = k; 表示: 第i行的第k个位置放一个皇后。这样一个arr[n]的数组就可以表示一个可行解, 由于回溯,我们就可以求所有解。

/**
 * n皇后问题解决
 * @author lin
 *
 */
 
#include <iostream>
#include <cmath>
#include<time.h>
 
using namespace std;
/**皇后的数目*/
static int num;
/**下标i表示第几行,x[i]表示第i行皇后的位置,注意此处0行不用*/
static int *x;
/**解的数目*/
static int sum = 0;
 
 
/**
 * 判断第k行皇后可以放置的位置
 * @param k k表示第k行,X[K]k表示第k行上皇后的位置
 * @return boolean false表示此处不能放置皇后
 */
bool place( int k )
{
    for ( int j = 1; j < k; j++ )
    {
        /* 如果当前传入的第K行上的皇后放置的位置和其它皇后一个对角线(abs(x[k]- x[j])==abs(k-j)或一个直线上(x[j] == x[k]) */
        if ( abs( x[k] - x[j] ) == abs( k - j ) || x[j] == x[k] )
        {
            return(false);
        }
    }
    return(true);
}
 
 
/**
 * 一行一行的确定该行的皇后位置
 * @param t
 */
void backtrack( int t )
{
    if ( t > num )                  /* 如果当前行大于皇后数目,表示找到解了 */
    {
        sum++;
        /* 依次打印本次解皇后的位置 */
        for ( int m = 1; m <= num; m++ )
        {
            //cout << x[m];   /* 这一行用输出当递归到叶节点的时候,一个可行解 */
            //这里只是为了好看才写成下面的
            for(int k =1; k <= num;k++){
                if(k == x[m]){
                    cout << x[m] << ; 
                }else {
                    cout << * ;//用*表示没有被用到的位置 
                }
            }
            cout << endl;
 
        }
        cout << endl;
    } else {
        for ( int i = 1; i <= num; i++ )
        {
            x[t] = i;       /* 第t行上皇放在i列处 */
            if ( place( t ) )
            {
                /* 此处的place函数用来进行我们上面所说的条件的判断,如果成立,进入下一级递归 */
                backtrack( t + 1 );
            }
        }
    }
}
 
 
int main()
{
    cout<<请输入皇后数目:;
    cin>>num; 
 
    clock_t start,finish;
    double totaltime;//计算程序运行时间
    start=clock();//起始时间
 
    x   = new int[num + 1];     /* 此处注意加1,这里0行不用,1-num分别对应1-num行 */
    for ( int i = 0; i <= num; i++ )
        x[i] = 0;
    backtrack( 1 );                 /*传入第一个皇后,开始递归 */
    cout << 方案共有 << sum;
    delete[]x;
 
    finish=clock();//结束时间
    totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
    cout<<此程序的运行时间为<<totaltime<<秒!<<endl; 
}
 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guangod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值