目前仅给出部分程序示例,后续会逐步完善,代码仅供参考
第1章 算法概述 Chapter 1 Introduction
算法实现题1-1 统计数字问题 Problem 1.1 Counting
´
问题描述:
一本书的页码从自然数1开始顺序编码直到自然数 n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字 0。例如,第6页用数字6表示,而不是06或006等。数字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,2,…,9。
´
编程任务:
给定表示书的总页码的10进制整数n(1≤n≤10
9
) 。编程计算书的全部页码中分别用到多少次数字 0,1,2,…,9。
´
数据输入:
输入数据由文件名为
input.txt
的文本文件提供。
每个文件只有1行,给出表示书的总页码的整数
n
。
´
结果输出
:
程序运行结束时,将计算结果输出到文件
output.txt
中。输出文件共有10行,在第k行输出页码中用到数字k-1的次数,k=1,2,…,10
。
输入、
输出文件示例
示例代码:
#include<stdio.h>
#include<math.h>
int main(void)
{
FILE *fp1,*fp2; //定义文件指针
fp1=fopen("H:\\ch1\\prog11\\test\\input.in","r+"); // 打开输入数据文件
fp2=fopen("H:\\ch1\\prog11\\answer\\output.txt","w+"); //打开输出数据文件
int n; //书的页数
int temp,i; //定义临时变量和循环控制变量
fscanf(fp1,"%d",&n); //从文件中读取书的页数
int count[10] = {0}; //按0-9的顺序将它们用到的次数存进统计数组
for(i=1;i<=n;i++) //书页从第一页开始逐页往后数
{
temp=i; //将当前书页页数赋值给临时变量
while(temp)
{
count[temp%10]++; //统计书页个位使用的数字
temp=temp/10; //统计书页十位及以上书页使的数字
}
}
for(i=0;i<10;i++) //循环输出统计结果
{
fprintf(fp2,"数字%d用到的次数为%d\n",i,count[i]); //输出数字使用次数
}
fclose(fp1); //关闭输入数据文件
fclose(fp2); //关闭输出数据文件
return 0;
}
算法实现题1-2 字典序问题 Problem 1.2 Dictionary
´
问题描述:
在数据加密和数据压缩中常需要对特殊的字符串进行编码。给定的字母表A由26个小写英文字母组成A={a,b,…,z}。该字母表产生的升序字符串是指字符串中字母按照从左到右出现的次序与字母在字母表中出现的次序相同,且每个字符最多出现1次。例如,a,b,ab,bc,xyz等字符串都是升序字符串。现在对字母表A产生的所有长度不超过6的升序字符串按照字典序排列并编码如下。
1 | 2 | ... | 26 | 27 | 28 | ... |
a | b | ... | z | ab | ac | ... |
对于任意长度不超过 6 的升序字符串,迅速计算出它在上述字典中的编码。
´
编程任务:
对于给定的长度不超过 6 的升序字符串,编程计算出它在上述字典中的编码。
´
数据输入:
输入数据由文件名为
input.txt
的文本文件提供。
文件的第一行是一个正整数 k,表示接下来共有 k 行。
接下来的 k 行中,每行给出一个字符串。
´
结果输出
:
程序运行结束时,将计算结果输出到文件
output.txt
中。文件共有 k 行,每行对应于一
个字符串的编码。
输入、
输出文件示例
算法实现题1-3 最多约数问题 Problem 1.3 Divisors
´
问题描述:
正整数 x 的约数是能整除 x 的正整数。正整数 x 的约数个数记为 div(x)。例如,1,2,5,10 都是正整数 10 的约数,且 div(10)=4。设 a 和 b 是 2 个正整数,a≤b,找出 a 和 b 之间约数个数最多的数 x。
´
编程任务:
对于给定的 2 个正整数 a≤b,编程计算 a 和 b 之间约数个数最多的数。
´
数据输入:
输入数据由文件名为
input.txt
的文本文件提供。文件的第 1 行有 2 个正整数
a
和
b
。
´
结果输出
:
程序运行结束时,若找到的
a
和
b
之间约数个数最多的数是
x
,将 div(x)输出到文件
output.txt
中。
输入、
输出文件示例
算法实现题1-4 金币阵列问题 Problem 1.4 Coin Array
´
问题描述:
有
m ×
n
(
m ≤
100,
n ≤
100)
个金币在桌面上排成一个
m
行
n
列的金币阵列。每一枚金币或正面朝上或背面朝上。用数字表示金币状态,0
表示金币正面朝上,
1
表示背面朝上。金币阵列游戏的规则是:
(
1
)每次可将任一行金币翻过来放在原来的位置上;
(
2
)每次可任选
2
列,交换这
2
列金币的位置。
´
编程任务:
给定金币阵列的初始状态和目标状态,编程计算按金币游戏规则,将金币阵列从初始状态变换到目标状态所需的最少变换次数。
´
数据输入:
由文件
input.txt
给出输入数据。文件中有多组数据。文件的第
1
行有
1
个正整数
k
,表示有 k
组数据。每组数据的第
1
行有
2
个正整数
m
和
n
。以下的
m
行是金币阵列的初始状态,每行有 n
个数字表示该行金币的状态,
0
表示金币正面朝上,
1
表示背面朝上。接着的m行是金币阵列的目标状态。
´
结果输出
:
将计算出的最少变换次数按照输入数据的次序输出到文件
output.txt
。相应数据无解时输出-1
。
输入、
输出文件示例
算法实现题1-5 最大间隙问题 Problem 1.5 Maximum Gap
´
问题描述:
最大间隙问题:给定 n 个实数
x
1
,
x
2
,...
,
x
n
,求这 n 个数在实轴上相邻 2 个数之间的最大差值。假设对任何实数的下取整函数耗时O
(1)
,设计解最大间隙问题的线性时间算法。
´
编程任务:
对于给定的 n 个实数
x
1
,
x
2
,...
,
x
n
,编程计算它们的最大间隙。
´
数据输入:
输入数据由文件名为
input.txt
的文本文件提供。文件的第 1 行有 1 个正整数 n。接下来的 1 行中有 n
个实数
x
1
,
x
2
,...
,
x
n
。
´
结果输出
:
程序运行结束时,将找到的最大间隙输出到文件
output.txt
中。
输入、
输出文件示例
第2章 递归与分治策略 Chapter 2 Recursion and Divide and Conquer
算法实现题2-1 众数问题 Problem 2.1 Majority
´
问题描述:
给定含有
n
个元素的多重集合
S
,每个元素在
S
中出现的次数称为该元素的重数。多重集 S
中重数最大的元素称为众数。
例如,
S={1
,
2
,
2
,
2
,
3
,
5}
。
多重集
S
的众数是
2
,其重数为
3
。
´
编程任务:
对于给定的由 n 个自然数组成的多重集 S,编程计算 S 的众数及其重数。
´
数据输入:
输入数据由文件名为
input.txt
的文本文件提供。
文件的第 1 行多重集
S
中元素个数
n
;接下来的 n 行中,每行有一个自然数。
´
结果输出
:
程序运行结束时,将计算结果输出到文件 output.txt 中。输出文件有 2 行,第 1 行给出众数,第 2 行是重数。
输入、
输出文件示例
示例代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
FILE *fp1,*fp2; //定义文件指针
fp1=fopen("H:\\ch2\\prog21\\test\\input.txt","r+"); //打开输入文件
fp2=fopen("H:\\ch2\\prog21\\answer\\output.txt","w+"); //打开输出文件
int num,temp,count=-1,ret; //num为集合中元素个数;temp为临时变量;count为重数比较的临时变量,ret为元素在栈中对应的下标值
fscanf(fp1,"%d",&num); //将文件中第一个数字读出赋值给num(集合中元素个数)
int *buf; //定义栈指针
buf = (int*)malloc(sizeof(int)*5000000); //防止栈溢出,在堆区初始化
memset(buf,0,sizeof(int)*5000000); //把栈中每个元素初始为0
int data[num]; //定义数据数组,用于存放从文件中读出的元素
for (int i=0;i<num;i++)
{
fscanf(fp1,"%d",&data[i]); //遍历文件,将读出的元素依次存入data数组
temp=data[i]; //将data数组中的元素逐一放入栈中
buf[temp]++; //元素作为栈的下标,栈中数据便作为该元素出现的次数,即重数
}
for (int i = 0; i < num; i++)
{
if (buf[i] > count) //用于比较重数大小,确定出现次数最多的自然数,即众数
{
count = buf[i];
ret = i; //将最大重数在栈中的下标赋值给ret,ret即为众数
}
}
fprintf(fp2,"该数组中众数为%d\n重数为%d\n",ret,buf[ret]); //将结果输出至指定文件
free(buf); //释放栈空间
fclose(fp1); //关闭输入数据文件
fclose(fp2); //关闭输出数据文件
return 0;
}
算法实现题2-2 马的Hamilton周游路线问题 Problem 2.2 Knight’s Hamilton Tour
´
问题描述:
8
×
8
的国际象棋棋盘上的一只马,恰好走过除起点外的其它
63
个位置各一次,最后回到起点。这条路线称为一条马的 Hamilton
周游路线。对于给定的
m
´
n
的国际象棋棋盘,
m 和 n
均为大于
5
的偶数,且
|m-n|
≤
2
,试设计一个分治算法找出一条马的
Hamilton
周游路线。
´
编程任务:
对于给定的偶数
m
,
n
≥
6
,且
|m-n|
≤
2
,编程计算
m×
n
的国际象棋棋盘一条马的
Hamilton 周游路线。
´
数据输入:
由文件
input.txt
给出输入数据。第一行有
2
个正整数
m
和
n
,表示给定的国际象棋棋盘由 m
行,每行
n
个格子组成。
´
结果输出
:
程序运行结束时
,
将计算出的马的
Hamilton
周游路线用下面的
2
种表达方式输出到文件output.txt 中。
第
1
种表达方式按照马步的次序给出马的
Hamilton
周游路线。马的每一步用所在的方格坐标(x
,
y)
来表示。
x
表示行的坐标,编号为
0
,
1
,…,
m-1
;
y
表示列的坐标,编号为
0
,1,…,
n-1
。起始方格为(
0
,
0
)。
第
2
种表达方式在棋盘的方格中标明马到达该方格的步数。(
0
,
0
)方格为起跳步,并标明为第 1
步。
输入、
输出文件示例
算法实现题2-3 半数集问题 Problem 2.3 Half Multiset
´
问题描述:
给定一个自然数
n
,由
n
开始可以依次产生半数集
set(n)
中的数如下。
(1) n
∈
set(n)
;
(2)
在
n
的左边加上一个自然数,但该自然数不能超过最近添加的数的一半;
(3)
按此规则进行处理,直到不能再添加自然数为止。
例如,
set(6)={6,16,26,126,36,136}
。半数集
set(6)
中有
6
个元素。
注意半数集是多重集。
´
编程任务:
对于给定的自然数 n,编程计算半数集 set(n)中的元素个数。
´
数据输入:
输入数据由文件名为
input.txt
的文本文件提供。
每个文件只有 1 行,给出整数
n
。
(0<n<1000)
´
结果输出
:
程序运行结束时,将计算结果输出到文件 output.txt 中。输出文件只有 1 行,给出半数集 set(n)中的元素个数。
输入、
输出文件示例
算法实现题2-4 半数单集问题 Problem 2.4 Half Set
´
问题描述:
给定一个自然数
n
,由
n
开始可以依次产生半数集
set(n)
中的数如下。
(1) n
∈
set(n)
;
(2)
在
n
的左边加上一个自然数,但该自然数不能超过最近添加的数的一半;
(3)
按此规则进行处理,直到不能再添加自然数为止。
例如,
set(6)={6,16,26,126,36,136}
。半数集
set(6)
中有
6
个元素。
注意半数集不是多重集。集合中已经有的元素不再添加到集合中。
´
编程任务:
对于给定的自然数 n,编程计算半数集 set(n)中的元素个数。
´
数据输入:
输入数据由文件名为 input.txt 的文本文件提供。
每个文件只有 1 行,给出整数
n
。
(0<n<201)
´
结果输出
:
程序运行结束时,将计算结果输出到文件 output.txt 中。输出文件只有 1 行,给出半
数集 set(n)中的元素个数。
输入、
输出文件示例
算法实现题2-5 有重复元素的排列问题 Problem 2.5 Permutation with Repetition
´
问题描述:
设
R={
r
1
,
r
2
,...
,
r
n
}
是要进行排列的
n
个元素。其中元素
r
1
,
r
2
,...
,
r
n
可能相同。试设计一个算法,列出 R
的所有不同排列。
´
编程任务:
给定 n 以及待排列的 n 个元素。计算出这 n 个元素的所有不同排列。
´
数据输入:
由文件
input.txt
提供输入数据。文件的第
1
行是元素个数
n
,
1≤
n≤
500
。接下来的
1
行是待排列的 n
个元素。
´
结果输出
:
程序运行结束时,将计算出的
n
个元素的所有不同排列输出到文件
output.txt
中。文件最后 1
行中的数是排列总数。
输入、
输出文件示例
示例代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int f[100],a[1000]; //f数组记录每个字母的出现次数、a数组记录每一种排列
int i,n,ans; //i为for循环的临时控制变量,n为元素个数,ans为排列方法总数
char str[1000]; //str数组记录输入的元素
void dfs(int dep)
{
int r;
if (dep==n+1)
{
ans++;//记录方案总数
for (r=1;r<=n;++r)
printf("%c",a[r]+96);
printf("\n");
return;
}
for (r=1;r<=26;++r) //按每轮26个小写字母来搜索
if (f[r]>0)//如果这个字母没有取完
{
a[dep]=r;//a依然是记录数组,用来储存每一种排列
f[r]--;//计数器-1
dfs(dep+1);
f[r]++;//回溯一步
}
}
int main(void)
{
printf("请输入元素个数:");
scanf("%d",&n); //确定读入元素个数
printf("请输入元素:");
cin>>str;//将字符串输入str数组
for (i=0;i<n;++i)
f[str[i]-96]++;//记录每一个字母在字符串中出现了几次
dfs(1);//调用函数
printf("%d",ans); //输出排列方法总数
return 0;
}
算法实现题2-6 排列的字典序问题 Problem 2.6 Lexicographic Order
´
问题描述:
n
个元素
{
1,2,...
,
n
}
有
n!
个不同的排列。将这
n!
个排列按字典序排列,并编号为
0
,1,…,n!-1。每个排列的编号为其字典序值。例如,当
n=3
时,
6
个不同排列的字典序值如下:
字典序值 | 0 | 1 | 2 | 3 | 4 | 5 |
排列 | 123 | 132 | 213 | 231 | 312 | 321 |
´
编程任务:
给定 n 以及 n 个元素{
1,2,...
,
n
}的一个排列,计算出这个排列的字典序值,以及按字典序排列的下一个排列。
´
数据输入:
由文件
input.txt
提供输入数据。文件的第
1
行是元素个数
n
。接下来的
1
行是
n
个元素 {1,2,...
,
n
}
的一个排列。
´
结果输出
:
程序运行结束时,将计算出的排列的字典序值和按字典序排列的下一个排列输出到文件output.txt 中。文件的第一行是字典序值,第
2
行是按字典序排列的下一个排列。
输入、
输出文件示例
算法实现题2-7 集合划分问题 Problem 2.7 Set Partition
´
问题描述:
n
个元素的集合
{
1,2,...
,
n
}
可以划分为若干个非空子集。例如,当
n=4
时,集合
{1
,
2
,
3
,
4}
可以划分为
15
个不同的非空子集如下:
{{1}
,
{2}
,
{3}
,
{4}}
,
{{1
,
2}
,
{3}
,
{4}}
,
{{1
,
3}
,
{2}
,
{4}}
,
{{1
,
4}
,
{2}
,
{3}}
,
{{2
,
3}
,
{1}
,
{4}}
,
{{2
,
4}
,
{1}
,
{3}}
,
{{3
,
4}
,
{1}
,
{2}}
,
{{1
,
2}
,
{3
,
4}}
,
{{1
,
3}
,
{2
,
4}}
,
{{1
,
4}
,
{2
,
3}}
,
{{1
,
2
,
3}
,
{4}}
,
{{1
,
2
,
4}
,
{3}}
,
{{1
,
3
,
4}
,
{2}}
,
{{2
,
3
,
4}
,
{1}}
,
{{1
,
2
,
3
,
4}}
´
编程任务:
给定正整数 n,计算出 n 个元素的集合{
1,2,...
,
n
}可以划分为多少个不同的非空子集。
´
数据输入:
由文件
input.txt
提供输入数据。文件的第
1
行是元素个数
n
。
´
结果输出
:
程序运行结束时,将计算出的不同的非空子集数输出到文件
output.txt
中。
输入、
输出文件示例
算法实现题2-8 集合划分问题2 Problem 2.8 Set Partition 2
´
问题描述:
n
个元素的集合
{
1,2,...
,
n
}
可以划分为若干个非空子集。例如,当
n=4
时,集合
{1
,
2
,3,
4}
可以划分为
15
个不同的非空子集如下:
{{1}
,
{2}
,
{3}
,
{4}}
,
{{1
,
2}
,
{3}
,
{4}}
,
{{1
,
3}
,
{2}
,
{4}}
,
{{1
,
4}
,
{2}
,
{3}}
,
{{2
,
3}
,
{1}
,
{4}}
,
{{2
,
4}
,
{1}
,
{3}}
,
{{3
,
4}
,
{1}
,
{2}}
,
{{1
,
2}
,
{3
,
4}}
,
{{1
,
3}
,
{2
,
4}}
,
{{1
,
4}
,
{2
,
3}}
,
{{1
,
2
,
3}
,
{4}}
,
{{1
,
2
,
4}
,
{3}}
,
{{1
,
3
,
4}
,
{2}}
,
{{2
,
3
,
4}
,
{1}}
,
{{1
,
2
,
3
,
4}}
其中,集合
{{1
,
2
,
3
,
4}}
由
1
个子集组成;集合
{{1
,
2}
,
{3
,
4}}
,
{{1
,
3}
,
{2
,4}},
{{1
,
4}
,
{2
,
3}}
,
{{1
,
2
,
3}
,
{4}}
,
{{1
,
2
,
4}
,
{3}}
,
{{1
,
3
,
4}
,
{2}}
,
{{2
,3,
4}
,
{1}}
由
2
个子集组成;集合
{{1
,
2}
,
{3}
,
{4}}
,
{{1
,
3}
,
{2}
,
{4}}
,
{{1
,
4}
,{2},
{3}}
,
{{2
,
3}
,
{1}
,
{4}}
,
{{2
,
4}
,
{1}
,
{3}}
,
{{3
,
4}
,
{1}
,
{2}}
由
3
个子集组成;集合{{1}
,
{2}
,
{3}
,
{4}}
由
4
个子集组成。
´
编程任务:
给定正整数 n 和 m,计算出 n 个元素的集合{
1,2,...
,
n
}可以划分为多少个不同的由 m 个非空子集组成的集合。
´
数据输入:
由文件
input.txt
提供输入数据。文件的第
1
行是元素个数
n
和非空子集数
m
。
´
结果输出
:
程序运行结束时,将计算出的不同的由
m
个非空子集组成的集合数输出到文件
output.txt中。
输入、
输出文件示例
算法实现题2-9 双色Hanoi塔问题 Problem 2.9 Bicolor Towers of Hanoi
´
问题描述:
设 A、B、C 是 3 个塔座。开始时,在塔座 A 上有一叠共 n 个圆盘,这些圆盘自下而上,由大到小地叠在一起。各圆盘从小到大编号为 1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。现要求将塔座 A 上的这一叠圆盘移到塔座 B 上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则:
规则(1):每次只能移动 1 个圆盘;
规则(2):任何时刻都不允许将较大的圆盘压在较小的圆盘之上;
规则(3):任何时刻都不允许将同色圆盘叠在一起;
规则(4):在满足移动规则(1)-(3)的前提下,可将圆盘移至 A,B,C 中任一塔座上。
试设计一个算法,用最少的移动次数将塔座 A 上的 n 个圆盘移到塔座 B 上,并仍按同样顺序叠置。
´
编程任务:
对于给定的正整数
n
,编程计算最优移动方案。
´
数据输入:
由文件
input.txt
给出输入数据。第
1
行是给定的正整数
n
。
´
结果输出
:
将计算出的最优移动方案输出到文件
output.txt
。文件的每一行由一个正整数
k
和
2
个
字符
c1
和
c2
组成,表示将第
k
个圆盘从塔座
c1
移到塔座
c2
上。
输入、
输出文件示例
算法实现题2-10 标准2维表问题 Problem 2.10 Standard 2´n Table
´
问题描述:
设
n
是一个正整数。
2
×
n
的标准
2
维表是由正整数
1
,
2
,…,
2n
组成的
2×
n
数组,该数组的每行从左到右递增,每列从上到下递增。2
´
n
的标准
2
维表全体记为
Tab(n)
。例如,当 n=3
时
Tab(3)
如下:
´
编程任务:
给定正整数
n
,计算
Tab(n)
中
2
´
n
的标准
2
维表的个数。
´
数据输入:
由文件
input.txt
给出输入数据。第一行有
1
个正整数
n
。
´
结果输出
:
将计算出的
Tab(n)
中
2
´
n
的标准
2
维表的个数输出到文件
output.txt
。
输入、
输出文件示例
算法实现题2-11 整数因子分解问题 Problem 2.11 Integer Factorization
´
问题描述:
大于
1
的正整数
n
可以分解为:
n=x
1
*x
2
*
…
*x
m
。
例如,当
n=12
时,共有
8
种不同的分解式:
12=12
;
12=6*2
;
12=4*3
;
12=3*4
;
12=3*2*2
;
12=2*6
;
12=2*3*2
;
12=2*2*3
。
´
编程任务:
对于给定的正整数
n
,编程计算
n
共有多少种不同的分解式。
´
数据输入:
由文件
input.txt
给出输入数据。第一行有
1
个正整数
n (1
≤
n
≤
2000000000)
。
´
结果输出
:
将计算出的不同的分解式数输出到文件
output.txt
。
输入、
输出文件示例