本人能力有限,发出只为帮助有需要的人。
建议同学们自己写完后再进行讨论。
其中的代码均没能在oj上进行测试,因此可能有误,请谅解。
除此以外部分题目设计深度优先搜索,因此可以分别用递归和堆栈实现,堆栈方法为了方便是用c++写的。
1. 正整数分解
题目描述:正整数n,按第一项递减的顺序依次输出其和等于n的所有不增的正整数和式。
输入:一个正整数n(0<n≤15)。
输出:每行输出如样例所示,和等于n的不增正整数和式,数字和运算符间无符号,最后一行结尾有一个回车换行符。
样例:
输入: 4
输出: 4=3+1 4=2+2 4=2+1+1 4=1+1+1+1
//此题思路为递归解DFS问题
#include<stdio.h>
int n;
int a[100]={0};
int check(int sit);//flag标记拆分的数的下标
void dfs(int x,int sit)//x表示被拆分的数,sit表示被拆分的数在数值中的位置
{
int i,k;
for(i=x-1;i>0;i--)//从后向前阅历
{
a[sit]=i;
a[sit+1]=x-i;//将下一位赋值成x-i,实现对数组中sit位置的拆分
if(check(sit+1))
{
int tem=0;
printf("%d=",n);//注意控制输出格式
for(int i=0;i<=sit+1;i++)
{
if(tem)
printf("+");
tem=1;
printf("%d",a[i]);
}
printf("\n");
}
if(a[sit+1]>1)
dfs(x-i,sit+1);//拆分后的数大于一则递归
}
}
int check(int sit)//检查是否递减
{
for(int i=0;i<sit;i++)
if(a[i]<a[i+1])
return 0;//如果出现前一位小于后一位则不递增
return 1;
}
int main(void)
{
scanf("%d",&n);
dfs(n,0);//进行深搜操作
return 0;
}
2. N皇后问题
题目描述:
八皇后问题由高斯(C. F. Gauss)最早在1850年提出并研究,但并未完全解决。N皇后问题指在一个N×N的棋盘上放置N个皇后,使任意两个皇后都不能互相攻击。按国际象棋规则,两个皇后,若在同一行上,或在同一列上, 或在同一条斜线上, 则她们可以互相攻击。下图即满足八皇后条件的一种棋局。
编写程序给出满足条件的棋局数目。
输入:一个正整数N(0<N≤13)输出:棋局数目
样例1:
输入: 2
输出: 0
样例2:
输入: 8
输出: 92
以下是递归写法(C)
#include <stdio.h>
int N;
int num=0;//作为所有可能的计数
int queenSit[10];//N皇后的本质就是一个一维数组(其每个皇后所在的行数不同,不妨设置为递增,所以只需要一维数组表示其列数即可)
int check(int *sit,int step)//检查皇后位置数组是否合法
{
for(int i=0;i<=step;i++)//截止到有皇后的位置
for(int j=i+1;j<=step;j++)//二维变量检测
{
if(sit[i]==sit[j])//检测时候存在相同元素(即时候一列中有两个皇后)
return 0;//不用检测一行中是否重复,因为建立时就设置好了不可能重复与=
else if(sit[i]==sit[j]-(j-i))//j-i为两个元素的距离,此处检测对角线是否重复
return 0;
else if(sit[i]==sit[j]+(j-i))//与上面的原理相同
return 0;
}
return 1;//合法返回1
}
void dfs(int *sit,int step)//递归表示DFS(递归的本质与栈相似)
{
if(step==N)
num++;//找的合理的解,解法加一
int *tmSit=sit;
if(step<N)
for(int i=0;i<N;i++)//将下一位的所有可能阅历
{
tmSit[step]=i;//构建新的递归元素
if(check(tmSit,step))//检查时候合理
dfs(tmSit,step+1);
}
}
int main(void)
{
scanf("%d",&N);
for(int i=0;i<N;i++)
{
queenSit[0]=i;//此题有N种初始情况,全部阅历
dfs(queenSit,1);//递归的初始step为1
}
printf("%d",num);
return 0;
}
以下为堆栈写法(c++)
#include <iostream>
#include <stack>
#include <algorithm>
#include <cstring>//注意memcpy在此头文件中
using namespace std;
int N;//将N设置为全局变量
struct node
{
int sit[10];//八皇后的本质就是一维数组(其每个皇后所在的行数不同,不妨设置为递增,所以只需要一维数组表示其列数即可)
int step;//表示此时数组中有step+1个皇后
};//用结构体方便些,能间接赋值数组
stack<node>canBe;//DFS核心就是建立堆栈
void buildStart(void)//此题的阅历没有一个指定的起点,所以将可能的8种情况全部放入堆栈之中
{
int start[N];
for(int i=0;i<N;i++)//将start初始化使其全部值都为-1
start[i]={-1};
for(int i=0;i<N;i++)//将八种情况都放进堆栈之中
{
start[0]=i;
struct node startNode;
startNode.step=0;
memcpy(startNode.sit,start,sizeof(start));//数组的复制操作
canBe.push(startNode);
}
}
int check(int *sit,int step)//检查皇后位置数组是否合法
{
for(int i=0;i<=step;i++)//截止到有皇后的位置
for(int j=i+1;j<=step;j++)//二维变量检测
{
if(sit[i]==sit[j])//检测时候存在相同元素(即时候一列中有两个皇后)
return 0;//不用检测一行中是否重复,因为建立时就设置好了不可能重复与=
else if(sit[i]==sit[j]-(j-i))//j-i为两个元素的距离,此处检测对角线是否重复
return 0;
else if(sit[i]==sit[j]+(j-i))//与上面的原理相同
return 0;
}
return 1;//合法返回1
}
int main(void)
{
int num=0;
cin>>N;//输入N
buildStart();
while(!canBe.empty())//当堆栈为空此题才跳出循环
{
struct node temNode;
temNode=canBe.top();
canBe.pop();//用堆栈表示BFS的核心
if(temNode.sit[N-1]!=-1)//如果最后一位都有元素,则说明构建成功
{
num++;//总数加一
continue;//进行下一轮的while循环
}
for(int k=0;k<N;k++)//试探下一行的八个位置
{
int temSit[N];
memcpy(temSit,temNode.sit,sizeof(temSit));
temSit[temNode.step+1]=k;//将数组的下一位赋值成k
if(check(temSit,temNode.step+1))//检测是否合理
{
struct node newNode;
newNode.step=temNode.step+1;//皇后个数加一
memcpy(newNode.sit,temSit,sizeof(temSit));
canBe.push(newNode);//将新的皇后位置加入堆栈
}
}
}
cout<<num;
return 0;
}
3.八皇后本质不同的解
题目描述:
如上题所述,当N=8时,一共有92种可能。如果去除其中上下对称、左右对称棋局、主副对角线对称棋局和旋转后重复棋局,则有12种完全不同的棋局。编写程序,输出这12种棋局。
输入:
无
输出:
共12行,每行输出1种棋局,
例如,第一行输出 No1:1 5 8 6 3 7 2 4(冒号为西文冒号且前后无多余字符,冒号后的每个数字后均有一个西文空格),
其中No1 表示这是第1种棋局;后续数字序列表示八皇后所在位置,数值本身表示某个皇后在棋盘上的行坐标,该数值所在位置表示该皇后的列坐标(>0),例如,数字5位于序列的第2位,表示棋盘上第5行第2列有一个皇后;数字4位于序列的第8位,表示棋盘上第4行第8列有一个皇后,由此,这8个数字描述了一种棋局。12种棋局的输出顺序:字典序(参考样例)。
样例:
输入:(无)
输出: No1:1 5 8 6 3 7 2 4 No2:1 6 8 3 7 4 2 5 ……(此处省略10行,分别表示No3至No12棋局)
以下为递归写法(c)
#include <stdio.h>
int num=0;//作为所有可能的计数
int queenSit[10];//N皇后的本质就是一个一维数组(其每个皇后所在的行数不同,不妨设置为递增,所以只需要一维数组表示其列数即可)
int flag=0;
int check(int *sit,int step)//检查皇后位置数组是否合法
{
for(int i=0;i<=step;i++)//截止到有皇后的位置
for(int j=i+1;j<=step;j++)//二维变量检测
{
if(sit[i]==sit[j])//检测时候存在相同元素(即时候一列中有两个皇后)
return 0;//不用检测一行中是否重复,因为建立时就设置好了不可能重复与=
else if(sit[i]==sit[j]-(j-i))//j-i为两个元素的距离,此处检测对角线是否重复
return 0;
else if(sit[i]==sit[j]+(j-i))//与上面的原理相同
return 0;
}
return 1;//合法返回1
}
void dfs(int *sit,int step)//递归表示DFS(递归的本质与栈相似)
{
if(step==8)
{
num++;//找的合理的解,解法加一
if(flag)
printf("\n");
flag=1;
printf("No%d.",num);
for(int i=0;i<8;i++)
{
printf("%2d",sit[i]+1);
}
}
int *tmSit=sit;
if(step<8)
for(int i=0;i<8;i++)//将下一位的所有可能阅历
{
tmSit[step]=i;//构建新的递归元素
if(check(tmSit,step))//检查时候合理
dfs(tmSit,step+1);
}
}
int main(void)
{
for(int i=0;i<8;i++)
{
queenSit[0]=i;//此题有N种初始情况,全部阅历
dfs(queenSit,1);//递归的初始step为1
}
return 0;
}
以下为堆栈写法(c++)
#include <iostream>
#include <stack>
#include <algorithm>
#include <cstring>//注意memcpy在此头文件中
using namespace std;
struct node
{
int sit[8];//八皇后的本质就是一维数组(其每个皇后所在的行数不同,不妨设置为递增,所以只需要一维数组表示其列数即可)
int step;//表示此时数组中有step+1个皇后
};//用结构体方便些,能间接赋值数组
stack<node>canBe;//DFS核心就是建立堆栈
void buildStart(void)//此题的阅历没有一个指定的起点,所以将可能的8种情况全部放入堆栈之中
{
int start[8];
for(int i=7;i>=0;i--)//将start初始化使其全部值都为-1
start[i]={-1};
for(int i=7;i>=0;i--)//将八种情况都放进堆栈之中(调整栈中元素位置方便输出)
{
start[0]=i;
struct node startNode;
startNode.step=0;
memcpy(startNode.sit,start,sizeof(start));//数组的复制操作
canBe.push(startNode);
}
}
int check(int *sit,int step)//检查皇后位置数组是否合法
{
for(int i=0;i<=step;i++)//截止到有皇后的位置
for(int j=i+1;j<=step;j++)//二维变量检测
{
if(sit[i]==sit[j])//检测时候存在相同元素(即时候一列中有两个皇后)
return 0;//不用检测一行中是否重复,因为建立时就设置好了不可能重复与=
else if(sit[i]==sit[j]-(j-i))//j-i为两个元素的距离,此处检测对角线是否重复
return 0;
else if(sit[i]==sit[j]+(j-i))//与上面的原理相同
return 0;
}
return 1;//合法返回1
}
int main(void)
{
int num=0;
buildStart();
while(!canBe.empty())//当堆栈为空此题才跳出循环
{
struct node temNode;
temNode=canBe.top();
canBe.pop();//用堆栈表示BFS的核心
if(temNode.sit[7]!=-1)//和八皇后问题不同的就是此处输出
{
num++;
cout<<"No"<<num<<".";
for(int i=0;i<8;i++)
cout<<temNode.sit[i]+1<<" ";//注意输出格式
cout<<endl;
continue;
}
for(int k=7;k>=0;k--)//试探下一行的八个位置(调整栈中元素位置方便输出)
{
int temSit[8];
memcpy(temSit,temNode.sit,sizeof(temNode.sit));
temSit[temNode.step+1]=k;//将数组的下一位赋值成k
if(check(temSit,temNode.step+1))//检测是否合理
{
struct node newNode;
newNode.step=temNode.step+1;//皇后个数加一
memcpy(newNode.sit,temSit,sizeof(temNode.sit));
canBe.push(newNode);//将新的皇后位置加入堆栈
}
}
}
return 0;
}