题目描述
宿舍里好多好多有趣的事!
7890653今天看到不知何时流行的五子棋,在宿舍里拿个本子,画一些格子,一个棋盘就做好了。
当7890653把目光放到棋上,突发奇想……
在一个 5*5 的棋盘内,放上n颗棋子,其中(5<=n<=25);
这n颗棋子可以不同的放到任何一个地方---在棋盘内。于是呼,便会有五颗棋子排成一行,或一列,或两条对角线,不同的放法,就会出现多少排五子的排列。
本题你要做的是,给你一个n,你找出不同放法出现的排列(设为k),如:n=11
有(1是棋子,0是空格)
1 1 1 0 0 1 1 1 1 1
1 1 0 0 0 1 1 1 1 0
1 1 0 0 0 1 1 0 0 0
1 1 0 0 0 0 0 0 0 0
1 1 0 0 0 k=2; 0 0 0 0 0 k=1;
只有这两种k值,(注意k不重复),你要输出的便是k值的和。
也就是1+2=3
输入格式
输入一个数n, 占一行!
其中(5<=n<=25);
输出格式
输出一个k值的总和!(想也不用想k的范围是1<=k<=12的);
样例输入
11
样例输出
3
解题思路:
这道题比较麻烦,需要先做一个五子棋摆放横竖的子函数,我就起名为cnm,其次为了好记录是否下棋,我们把a定义为布尔型,在1~5的循环内判断横竖摆放是否为真,为真计数器就加加,在循环外判断是否为对角线,如果为真用一个布尔型变量记录为真(这里我用的是d).
接下来就是子函数(dfs),我们要先判断放不了的情况,也就是说n+1或i==6,还需要一个判断就是sum==n+1,就是放不下棋子或都用完的情况,这是就可以调用cnm,这个循环结束后就可以用return ;跳到上一层,完了之后我们还要判断j用完的情况,就是一个if(j==6)然后递归,如果没有用完的话就else,else内我们要先记录a[i][j]为真,接着就是递归,再记录a[i][j]为假,继续递归,最后记录a[i][j]为假,这就是子函数部分。
最后是主函数,输入不用多说,需要一个1~12(大于12)的循环,因为k的范围是1~12,在里面判断d[i]是否为真,如果为真就用一个计数器+=i,最后我们只需要输出那个计数器即可。(这题真令人痛苦)
直接上代码!!!!!
#include <iostream>
#include <cstring>
using namespace std;
bool a[6][6],d[15];
int ans=0,n;
void cnm()
{
int s=0;
for(int i=1;i<=5;i++){
if(a[i][1]&&a[i][2]&&a[i][3]&&a[i][4]&&a[i][5]) s++;
if(a[1][i]&&a[2][i]&&a[3][i]&&a[4][i]&&a[5][i]) s++;
}
if(a[1][1]&&a[2][2]&&a[3][3]&&a[4][4]&&a[5][5]) s++;
if(a[1][5]&&a[2][4]&&a[3][3]&&a[4][2]&&a[5][1]) s++;
d[s]=true;
}
void dfs(int i,int j,int sum){
if(i==6||sum==n+1)
{
if(sum==n+1)
{
cnm();
}
return ;
}
if(j==6) dfs(i+1,1,sum);
else
{
a[i][j]=1;
dfs(i,j+1,sum+1);
a[i][j]=0;
dfs(i,j+1,sum);
a[i][j]=0;
}
}
int main(){
cin>>n;
dfs(1,1,1);
for(int i=1;i<=15;i++)
{
if(d[i])ans+=i;
}
cout<<ans;
return 0;
}