1.
题目名称:正整数分解
题目描述:正整数n,按第一项递减的顺序依次输出其和等于n的所有不增的正整数和式。
输入:一个正整数n(1<n≤15)。
输出:每行输出如样例所示,和等于n的不增正整数和式,数字和运算符间无符号,最后一行结尾有一个回车换行符。
样例:
输入: | |
4 |
输出: | |
4=3+1 | |
4=2+2 | |
4=2+1+1 | |
4=1+1+1+1 |
方案一,这里我最开始用穷举法,但最后过程过于复杂,相较下,方案二更简单,大家可以略过方案一。
#define _CRT_SECURE_NO_WARNINGS
#include"stdio.h"
#include"string.h"
#include"assert.h"
int a[150][16];
int jud(const int a[][16],int m,int i)//(m为n-k,i为行)
{
//情况1返回0,情况2返回正数该正数为非0列的位置,情况3返回负数,绝对值为非0列的位置
if (a[i][m] != 0)
return 0;
while(a[i][m] == 0)
{
m--;
assert(m);//不许m==0
}
if(a[i][m]==1)
return m;//m为非0列
if (a[i][m] != 1)
return -m;
else return 200;
}
int sum(const int a[][16], int i,int m)//i为行数,m为需求和的列数(即n-k+1)
{
int n;
int sum1 = 0;
for (n = 0; n < m; n++)
{
sum1 += a[i][n];
}
return sum1;
}
//input处理正整数分解时第一个分解出的数(即等号右边第一个数)相同的情况,分解正数,n一共处理n-1次,将分解出的数据(即n的分解等式右端不包括+的部分)填入数组a【】【】
int input(int n,int k,int i)//(k为分解后的式子的第一个数,i为待填充行,每次填完一行i++,返回待填充行)
{
int m,z;
a[i][0] = k; a[i][1] = n-k;
//穷举法处理
//(1)判断除等号右边第一个数k外,至多有n-k个数,且不大于n-k,人工填入一行(n=(n-k)+k的数据n-k和k)后,剩余的不大于n-k-1
//(2)数据准备(这里确保穷举的数据递减)
// 如果k>=n-k
// 将a的第i行除第0列外的n-k列填入n-k-1,
// 如果k<n-k
// 则第i行除0列外n-k列填k
//(3)穷举(在保证数据递减的情况下枚举并判断)
//每次从最后一列(即第n-k列(有0列))减一,每次减一后判断是否该行和为n,若为n就是一种可能,数据填入该行,准备下次填入
//这有三种情况
//1、最后一列非0,正常减一
//2、最后一列为0,依次向前寻找非0列,找到第一个非0列为1,则该列减一,
//3、最后一列为0,依次向前寻找非0列,找到第一个非0列不为1,则减一后将减一后的该数据往后赋值,直到第n-k列被赋值
//上述3种情况通过限制递减,可保证每种正确情况均可考虑
//(4)所有数据存入a[][]数组,即可打印
if (n - k > 2)
{
if (k >= n - k)
{
i++;
for (m = 1; m <= n - k; m++)
{
a[i][m] = n - k - 1;
}
}
else {
for (m = 1; m <= n - k; m++)
a[i][m] = k;
}
while (a[i][1] != 1)
{
assert(i!=200);
a[i][0] = k;//先填充第一个数
while (sum(a, i, n - k + 1) != n)
{
z = jud(a, n - k, i);
assert(z != 200);
if (z == 0)
{
a[i][n - k ]--;
}
if (z < 0)
{
z = -z;
a[i][z]--;
for (m = z + 1; m <= n - k; m++)
{
a[i][m] = a[i][z];
}
z = -z;
}
if (z > 0)
a[i][z]--;
}
if (a[i][1] == 1)//因为考虑不周导致while(a[i][1]限制不完全
//,使这个if语句后面代码在不和条件时多执行了一次,因此这里用if限制一下
return i + 1;
i++;
memcpy(a[i], a[i - 1], 16 * sizeof(int));
z = jud(a, n - k, i);
assert(z != 200);
if (z == 0)
{
a[i][n - k]--;
}
if (z < 0)
{
z = -z;
a[i][z]--;
for (m = z + 1; m <= n - k; m++)
{
a[i][m] = a[i][z];
}
z = -z;
}
if (z > 0)
a[i][z]--;
}
return i;
}
if (n - k == 2)
{
i++;
a[i][0] = k; a[i][1] = a[i][2]=1;
return i+1;
}
if (n - k == 1)
{
return i + 1;
}
else return -1;
}
int main()
{
bool flag = true;
int n,c=0,i=0;
scanf("%d",&n);
if (n == 1)
{
printf("1=1\n");
return 0;
}
for (int l = n-1; l > 0; l--)
{
c = input(n,l,c);
assert(c != -1);
}
for (int l = 0; l <=c; l++)
{
i = 0;
while (a[l][i] != 0)
{
if (flag)
{
printf("%d=%d", n,a[l][i]);
flag = 0;
}
else printf("+%d",a[l][i]);
i++;
if (a[l][i] == 0)
{
printf("\n");
flag = 1;
}
}
}
}
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int a[20] = {0};
void F(int sum, int ub, int p)
{
if (sum == 0) {
printf("%d", a[0]);
printf("%c",a[1]);
for (int j = 2; j <= p - 2; j++)
{
printf("%d+",a[j]);
}
printf("%d",a[p-1]);
printf("\n");
}
for (int i = sum; i >= 1; i--)
{
if (i <= ub)
{
a[p] = i;
F(sum - i, i, p + 1);
}
}
}
int main()
{
int m;
scanf("%d",&m);
a[0] = m; a[1] = '=';
F(m, m - 1, 2);
printf("\n");
return 0;
}
2.
题目名称:N皇后问题
题目描述:
八皇后问题由高斯(C. F. Gauss)最早在1850年提出并研究,但并未完全解决。N皇后问题指在一个N×N的棋盘上放置N个皇后,使任意两个皇后都不能互相攻击。按国际象棋规则,两个皇后,若在同一行上,或在同一列上, 或在同一条斜线上, 则她们可以互相攻击。下图即满足八皇后条件的一种棋局。
编写程序给出满足条件的棋局数目。

输入:一个正整数N(0<N≤13)输出:棋局数目
样例1:
输入: | |
2 |
输出: | |
0 |
样例2:
输入: | |
8 |
输出: | |
92 |
#define _CRT_SECURE_NO_WARNINGS
#include"stdio.h"
int z = 0;
int arr[14], m,t=0;
int check(int r)//判断数组数据是否合适,合适返回1,否者返回0
{
int i;
for (i = 1; i < r; i++)
{
if (arr[r] == arr[i])return 0;
if (arr[r] - r == arr[i] - i)return 0;
if (arr[r] + r == arr[i] + i)return 0;
}
return 1;
}
void extend(void)
{
m++;
arr[m] = 1;
}
void out(void)
{
t++;
}
void change( int N)
{
while (arr[m] == N&&m>0)
{
m--;
}
if (arr[m] < N&&m>0)
arr[m]++;
}
int main()
{
arr[0] = 0; arr[1] = 1; m = 1;
int N;
scanf("%d", &N);
if (N == 1)
{
printf("1"); return 0;
}
while (m > 0)
{
if (check(m))
{
if (m == N)
{
out();
change(N);
}
else extend();
}
else change(N);
}
printf("%d",t);
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棋局) |
#define _CRT_SECURE_NO_WARNINGS
#include"stdio.h"
#include"string.h"
int z = 0;
int arr[9], k[100][9], j[100][9] = {0}, m, t = 0;
int check(int r)//判断数组数据是否合适,合适返回1,否者返回0
{
int i;
for (i = 1; i < r; i++)
{
if (arr[r] == arr[i])return 0;
if (arr[r] - r == arr[i] - i)return 0;
if (arr[r] + r == arr[i] + i)return 0;
}
return 1;
}
void extend(void)
{
m++;
arr[m] = 1;
}
void out(void)
{
t++;
}
void change(int N)
{
while (arr[m] == N && m > 0)
{
m--;
}
if (arr[m] < N && m>0)
arr[m]++;
}
void copy(void)
{
while (m > 0)
{
if (check(m))
{
if (m == 8)
{
out();
memcpy(k[t], arr, 9 * sizeof(int));
change(8);
}
else extend();
}
else change(8);
}
}
void _memmove(void)//用于将最终结果移到j数组中
{
int q = 0;
for (int n = 1; n <= 92; n++)
{
if (k[n][0] == 0)
{
memmove(j[q], k[n], 9 * sizeof(int));
q++;
}
}
}
int check(int c,int i, int n,int m)
{
switch (c)
{
case 1: return ((k[i][m] + k[n][m]) == 9);//检查左右对称
case 2:return (k[i][m] == k[n][9 - m]);//检查上下对称
case 3:return (k[n][k[i][m]] == m);//检查主对角线对称
case 4:return (k[n][9 - k[i][m]] == 9 - m);//检查副对角线对称
case 5:return (k[n][9 - k[i][m]] == m);//检查顺时针转90°
case 6:return (k[n][9 - m] == 9 - k[i][m]);//检查顺时针转180°
case 7:return (k[n][k[i][m]] == 9 - m);//检查逆时针转90°
}
}
void jud(int(*p)(int ,int ,int,int))//用于循环并判断对称情况
{
int i = 1, m = 1, n = 1,c=1;
for (c = 1; c <= 7; c++)
{
for (i = 1; i < 92; i++)
{
for (n = i + 1; n <= 92; n++)
for (m = 1; m <= 8; m++)
{
if (p(c, i, n, m))
{
if (m == 8)
k[n][0] = 1;//这里判断出为重复情况,k[n][0]置1表示重复
}
else break;
}
}
}
}
int main()
{
arr[0] = 0; arr[1] = 1; m = 1;
copy();//用于生成数据并copy到k数组中
int q = 1;
jud(check);
_memmove();
for (q = 0; q < 12; q++)
{
printf("No%d:", q+1);
for (int b = 1; b < 9; b++)
{
printf("%d ", j[q][b]);
if (b == 8)
printf("\n");
}
}
return 0;
}
这里我使用教材上的试探法得出初始数据,但听说用DFS算法生成初始的未排序数据更快更简单,有兴趣可以了解一下



2359

被折叠的 条评论
为什么被折叠?



