Reference: 《算法竞赛入门经典》(刘汝佳)第一版、第二版
------------------------------------------------------------------------------------------------------------------------------------------------
1. 第2章 小结与习题
(1) Ex1 第一版P32 2-7 近似计算
#include <iostream>
//#include <cstdio>
//#include <ctime>
#include <fstream>
#include <cmath>
//#include <iomanip>
using namespace std;
ifstream fin("input.txt");
ofstream fout("output.txt");
// compute the value of PI
int main()
{
double pi = 0;
int i = 1;
double temp = static_cast<double>(1)/(2*i-1);
while(fabs(temp - 1e-6) > 1e-9) // the last item is lesser than 1e-6
{
pi += temp;
i++;
temp = static_cast<double>(1)/(2*i-1);
if(i%2==0)
temp = -temp;
}
pi += temp;
pi = 4*pi;
fout << pi << endl;
return 0;
}
(2)Ex2 第一版P32 2-8 子序列的和
#include <iostream>
//#include <cstdio>
//#include <ctime>
#include <fstream>
#include <cmath>
#include <iomanip>
using namespace std;
ifstream fin("input.txt");
ofstream fout("output.txt");
// compute the value of PI
int main()
{
int n, m;
fin >> n >> m;
//long long n_square = n*n, m_square = m*m;
double result = 0.0;
for(long long i = n; i <= m; i++) // i的类型设为long long避免在i*i时发生溢出
{
result += static_cast<double>(1)/(i*i);
}
fout << setprecision(6) << result << endl; // setprecesion()设定有效位数而非小数的位数
return 0;
}
(3)Ex3 第一版P32 2-9 分数化小数
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int a, b, c;
fscanf(fin, "%d%d%d", &a, &b, &c);
double result;
result = static_cast<double>(a)/b;
fprintf(fout, "%.*f", c, result); // printf对于输出任意精度可以用此格式
fclose(fin);
fclose(fout);
return 0;
}
2. 第3章 数组和字符
(1)Ex1 第一版P34 3-1 开灯问题
#include <iostream>
#include <cstdio>
#include <fstream>
#define MAX_LEN 1000+10
using namespace std;
ifstream fin("input.txt");
ofstream fout("output.txt");
int a[MAX_LEN] = {0};
int main()
{
int n, k;
fin >> n >> k;
int i,j;
for(i = 1; i <= k; i++) // k个人按开关操作k次
{
for(j = 1; j <= n; j++)
{
if(j%i==0) // 进行按下开关的操作
a[j] = !a[j];
}
}
// 输出亮着的灯的编号
for(i = 1; i < n; i++)
if(a[i]==1)
fout << i << " ";
if(a[i]==1)
fout << i << endl;
else
fout << endl;
return 0;
}
(2)Ex2 第一版P35 3-2 蛇形填数
#include <iostream>
#include <cstring>
#define MAX_LEN 10
using namespace std;
int a[MAX_LEN][MAX_LEN];
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int n;
fscanf(fin, "%d", &n);
int x, y, num = 0;
memset(a, 0, sizeof(a));
num = a[x=0][y=n-1] = 1;
while(num < n*n)
{
while(x+1<n && !a[x+1][y]) // 向下移动至边界或已经有数填入的位置为止
a[++x][y] = ++num;
while(y-1>=0 && !a[x][y-1]) // 向左移动
a[x][--y] = ++num;
while(x-1>=0 && !a[x-1][y]) // 向上移动
a[--x][y] = ++num;
while(y+1<n && !a[x][y+1]) // 向右移动
a[x][++y] = ++num;
}
for(x = 0; x < n; x++)
{
for(y = 0; y < n; y++)
fprintf(fout, "%3d", a[x][y]); // 用%3d来输出保持格式对齐,不用输出空格
fprintf(fout, "\n");
}
fclose(fin);
fclose(fout);
return 0;
}
(3)第一版P37 3-3 竖式问题
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
char s[20], buf1[128];
int abc, de, temp1, temp2, temp3, count = 0, str_len;
bool is_not_found = true;
fscanf(fin, "%s", s);
for(abc = 100; abc <= 999; abc++)
{
for(de = 10; de <= 99; de++)
{
temp1 = abc*(de%10); // 竖式计算中的中间结果和最后结果
temp2 = abc*(de/10);
temp3 = abc*de;
// 用sprintf将数字转为字符串
sprintf(buf1, "%d%d%d%d%d", abc, de, temp1, temp2, temp3);
str_len = strlen(buf1);
for(int i = 0; i < str_len; i++)
{
if(strchr(s, buf1[i])==nullptr) // 有数字不在集合s中的情况
{
is_not_found = false;
break;
}
}
if(is_not_found)
{
fprintf(fout, "<%d>\n", ++count);
fprintf(fout, "%5d\nX%4d\n-----\n%5d\n%4d\n-----\n%5d\n\n",
abc, de, temp1, temp2, temp3);
}
is_not_found = true; // 一次循环结束重设标志is_not_found
}
}
fprintf(fout, "The number of solutions = %d\n", count);
fclose(fin);
fclose(fout);
return 0;
}
(4)第一版P41 3-4 回文串
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAX_LEN 5000+10
using namespace std;
char buf[MAX_LEN], temp[MAX_LEN], result[MAX_LEN];
void solve();
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
fgets(buf, sizeof(buf), fin);
solve();
fprintf(fout, "%s\n", result);
fclose(fin);
fclose(fout);
return 0;
}
void solve()
{
int buf_len= strlen(buf), m = 0;
int max = 0, front = 0, rear = 0;
for(int i = 0; i < buf_len; i++) // 提取出字母并转换为大写
{
if(isalpha(buf[i]))
{
temp[m] = i;
result[m++] = toupper(buf[i]);
}
}
for(int i = 0; i < m; i++)
{
for(int j = 0; i-j>=0 && i+j<=m-1; j++) // 奇数长回文串寻找
{
if(result[i-j]!=result[i+j])
break;
if(2*j+1>max)
{
max = 2*j+1;
front = temp[i-j];
rear = temp[i+j];
}
}
for(int j = 0; i-j>=0 && i+j+1<=m-1; j++) // 偶数长回文串查找
{
if(result[i-j]!=result[i+j+1])
break;
if(2*j+2>max)
{
max = 2*j+2;
front = temp[i-j];
rear = temp[i+j+1];
}
}
}
int i = 0;
for(; i+front <= rear; i++)
result[i] = buf[front+i];
result[i] = '\0';
}
(5)第二版P92 3-1 TeX中的引号
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAX_LEN 1000+10
using namespace std;
char buf[MAX_LEN];
int temp[MAX_LEN];
void solve();
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int i = 0;
char ch;
while((ch=fgetc(fin))!=EOF) // 将全文包括换行符读入buf
{
buf[i++] = ch;
}
buf[i] = '\0';
solve();
fprintf(fout, "%s\n", buf);
fclose(fin);
fclose(fout);
return 0;
}
void solve()
{
int count = 0, index = 0;
int buf_len = strlen(buf);
for(int i = 0; i < buf_len; i++)
{
if(buf[i]=='"')
{
count++;
temp[index++] = i; // 存储在buf中出现"的位置
}
}
for(int i = 0; i < count; i+=2)
{
buf[temp[i]] = '0'; // 代替“
}
}
(6)第二版P94 3-2 WERTYU
①
#include <cstdio>
#include <cstring>
char strings[] = "WERTYUIOP[]\\SDFGHJKL;'XCVBNM,./"; // 可能输入的错误字符组成的字符数组
char right_strings[] = "QWERTYUIOP[]ASDFGHJKL;ZXCVBNM,."; // 上述错误字符按位置对应的正确输入的字符数组
void solve(const char &ch, char &ans) // 对于输入字符ch,找到其对应的正确输入字符ans
{
int strings_len = strlen(strings);
int i;
bool is_found = false;
for(i = 0; i < strings_len; i++)
{
if(strings[i]==ch)
{
ans = right_strings[i];
is_found = true;
break;
}
}
if(!is_found)
ans = ch;
}
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
char ch, ans;
while(fscanf(fin, "%c", &ch)==1)
{
solve(ch, ans);
fprintf(fout, "%c", ans);
}
fclose(fin);
fclose(fout);
return 0;
}
②教材代码:
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAX_LEN 28
using namespace std;
char s[] = "`1234567890-=QWERTYUIOP[]\\ASDFGHJKL;'ZXCVBNM,./";
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
char ch;
int i;
while((ch=fgetc(fin))!=EOF)
{
for(i = 1; s[i] && s[i]!=ch; i++); // 找到ch在数组s中的索引i,读到数组结尾或者等于ch的位置为止
if(s[i])
fputc(s[i-1], fout);
else // ch不在数组s之中
fputc(ch, fout);
}
fclose(fin);
fclose(fout);
return 0;
}
(7)第二版P95 3-3 回文词
#include <cstdio>
#include <cstring>
char mirror[] = "AEHIJLMOSTUVWXYZ12358",
mirror_2[] = "A3HILJMO2TUVWXY51SEZ8";
bool is_palindrome(const char *s)
{
int len = strlen(s), i;
for(i = 0; i <= (len-1)/2; i++)
{
if(s[i] != s[len-i-1])return false;
}
return true;
}
bool is_mirrored(const char *s)
{
int len = strlen(s), i, j, mirror_len = strlen(mirror);
for(i = 0; i <= (len-1)/2; i++)
{
// 若s中字符不在mirror中则返回false
bool is_found = false;
for(j = 0; j < mirror_len; j++)
if(s[i] == mirror[j])
{
is_found = true;
break;
}
if(!is_found)return false;
if(s[len-i-1] != mirror_2[j])return false;
}
return true;
}
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
char s[20];
while(fscanf(fin, "%s", s)==1)
{
if(is_palindrome(s)&&is_mirrored(s))
fprintf(fout, "%s -- is a mirrored palindrome.\n\n", s);
else if(is_palindrome(s))
fprintf(fout, "%s -- is a regular palindrome.\n\n", s);
else if(is_mirrored(s))
fprintf(fout, "%s -- is a mirrored string.\n\n", s);
else
fprintf(fout, "%s -- is not a palindrome.\n\n", s);
}
fclose(fin);
fclose(fout);
return 0;
}
(8)第二版P98 3-4 猜数字游戏的提示
#include <cstdio>
#include <cstring>
#define MAX_LEN 128
using namespace std;
int answer[MAX_LEN], temp[MAX_LEN];
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int n, i = 0;
while(fscanf(fin, "%d", &n)==1 && n) // 当不到EOF且n不为0时继续循环
{
fprintf(fout, "Game %d:\n", ++i);
for(int j = 0; j < n; j++) // 输入数据到answer
fscanf(fin, "%d", &answer[j]);
while(true)
{
bool ended = 1;
int A = 0, B = 0;
for(int j = 0; j < n; j++) // 输入数据到temp
{
fscanf(fin, "%d", &temp[j]);
if(temp[j])
ended = 0;
if(temp[j]==answer[j])
A++;
}
if(ended) // 若输入的一行为全0则该组数据结束
break;
// 对于1-9进行遍历找到对于j的最大对应数的和B
// B-A即在两个序列都出现过但顺序不对的数量
for(int j = 1; j <= 9; j++)
{
int count1 = 0, count2 = 0;
for(int k = 0; k < n; k++)
{
if(answer[k]==j)count1++;
if(temp[k]==j)count2++;
}
B += (count1>count2)?count2:count1;
}
fprintf(fout, " (%d %d)\n", A, B-A);
}
}
fclose(fin);
fclose(fout);
return 0;
}
(9)第二版P101 3-5 生成元
#include <cstdio>
#include <cstring>
#define MAX_LEN 100000+10
using namespace std;
int y[MAX_LEN];
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int n;
memset(y, 0, sizeof(y));
int temp;
// 设置1-100000的数组对应的生成元
for(int i = 1; i <= 100000; i++)
{
temp = i;
n = 0;
while(temp)
{
n += temp % 10;
temp /= 10;
}
n += i;
y[n] = i;
}
while(fscanf(fin, "%d\n", &n)!=EOF)
fprintf(fout, "%d\n", y[n]);
fclose(fin);
fclose(fout);
return 0;
}
(10)第二版P102 3-6 环状序列
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX_LEN 100+10
using namespace std;
char sequence[MAX_LEN], temp[MAX_LEN], result[MAX_LEN];
void cmp(int str_len, int i)
{
int index = 0;
for(int j = i; j < str_len; j++)
temp[index++] = sequence[j];
for(int j = 0; j < i; j++)
temp[index++] = sequence[j];
temp[index] = '\0';
if(strcmp(temp, result)<0)
strcpy(result, temp);
}
void solve(int str_len)
{
int i;
strcpy(result, sequence);
for(i = 1; i < str_len; i++) // 遍历开头字符从索引1到str_len-1
{
cmp(str_len, i);
}
}
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int str_len = 0;
while(!feof(fin))
{
fscanf(fin, "%s", sequence);
str_len = strlen(sequence);
solve(str_len);
fprintf(fout, "%s\n", result);
}
fclose(fin);
fclose(fout);
return 0;
}
书本解法:
#include<stdio.h>
#include<string.h>
#define maxn 105
//环状串s的表示法p是否比表示法q的字典序小
int less(const char* s, int p, int q) {
int n = strlen(s);
for(int i = 0; i < n; i++)
// 通过模运算%进行比较,不用写两个循环从头比较
if(s[(p+i)%n] != s[(q+i)%n])
return s[(p+i)%n] < s[(q+i)%n];
return 0; //相等
}
int main() {
int T;
char s[maxn];
scanf("%d", &T);
while(T--) {
scanf("%s", s);
int ans = 0;
int n = strlen(s);
for(int i = 1; i < n; i++) // i对应字符开头的索引位置
if(less(s, i, ans)) ans = i;
for(int i = 0; i < n; i++)
putchar(s[(i+ans)%n]);
putchar('\n');
}
return 0;
}
(11)第一版P50 3-1 分数统计(stat)
#include <cstdio>
#include <cstring>
#define MAX_LEN 105
int record[MAX_LEN], frequency[MAX_LEN];
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
memset(frequency, 0, sizeof(frequency));
int i, n, maxn = 0;
while(fscanf(fin, "%d", &n)==1)
frequency[n]++;
// 遍历frequency搜寻出最大的出现个数
maxn = frequency[0];
for(i = 1; i <= 100; i++)
if(maxn < frequency[i])
maxn = frequency[i];
int index = 0;
for(int j = 0; j <= 100; j++)
if(frequency[j]==maxn)
record[index++] = j;
for(int j = 0; j < index; j++)
fprintf(fout, "%d\n", record[j]);
fclose(fin);
fclose(fout);
return 0;
}
(12)第一版P50 3-2 单词的长度(word)
#include <cstdio>
#include <cstring>
#define SIZE 100
char word[SIZE];
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int total_len = 0, count = 0;
while(fscanf(fin, "%s", word)!=EOF)
{
count++;
total_len += strlen(word);
}
fprintf(fout, "%.2f", static_cast<double>(total_len)/count);
fclose(fin);
fclose(fout);
return 0;
}
(13)第一版P50 3-3 乘积的末3位(product)
#include <cstdio>
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int result = 1, num = 1;
while(fscanf(fin, "%d", &num)!=EOF)
{
result *= num;
num = 1;
fgetc(fin); // 将空格和大写字符读取, 保证fscanf()正常读入数字到num
}
fprintf(fout, "%d", result%1000);
fclose(fin);
fclose(fout);
return 0;
}
(14)第一版P50 3-4 计算器(calculator)
#include <cstdio>
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int num1, num2, result;
char command;
while(fscanf(fin, "%d", &num1)!=EOF)
{
// 空格也是一个字符, 用do-while读入一个非空的操作符
do
{
fscanf(fin, "%c", &command);
}while(command == ' ');
fscanf(fin, "%d", &num2);
switch(command)
{
case '+':result = num1 + num2; break;
case '-':result = num1 - num2; break;
case '*':result = num1 * num2; break;
case '/':result = num1 / num2; break;
default:break;
}
fprintf(fout, "%d\n", result);
}
fclose(fin);
fclose(fout);
return 0;
}
(15)第一版P50 3-5 旋转(rotate)
#include <cstdio>
#define SIZE 128
char matrix[SIZE][SIZE];
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int matrix_size;
fscanf(fin, "%d", &matrix_size);
fgetc(fin); // 读入换行符
// 读入字符矩阵至二维数组
for(int i = 0; i < matrix_size; i++)
{
for(int j = 0; j < matrix_size; j++)
fscanf(fin, "%c", &matrix[i][j]);
fgetc(fin);
}
for(int j = matrix_size - 1; j >= 0; j--)
{
for(int i = 0; i < matrix_size; i++)
fprintf(fout, "%c", matrix[i][j]);
fprintf(fout, "\n");
}
fclose(fin);
fclose(fout);
return 0;
}
(16)第一版P50 3-6 进制转换1(base1)
#include <cstdio>
#define SIZE 128
int num[SIZE];
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int b, n, result = 0, count = 0;
fscanf(fin, "%d", &b);
fscanf(fin, "%d", &n);
while(n!=0)
{
num[count++] = n % b;
n = n / b;
}
for(int i = count-1; i >= 0; i--)
{
result *= 10;
result += num[i];
}
fprintf(fout, "%d", result);
fclose(fin);
fclose(fout);
return 0;
}
(17)第一版P50 3-7 进制转换2(base 2)
#include <cstdio>
#define SIZE 128
int num[SIZE];
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int b, n, result = 0, count = 0;
fscanf(fin, "%d", &b);
fscanf(fin, "%d", &n);
while(n!=0)
{
num[count++] = n % 10;
n = n / 10;
}
for(int i = count-1; i >= 0; i--)
{
result *= b;
result += num[i];
}
fprintf(fout, "%d", result);
fclose(fin);
fclose(fout);
return 0;
}
3. 第4章 函数和递归
(1)第一版P53 例题4-1 组合数
#include <cstdio>
#include <assert.h>
int factorial(int n)
// 计算n的阶乘
{
assert(n >= 0);
int i, result = 1;
for(i = 1; i <= n; i++)
result *= i;
return result;
}
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int m, n, result = 1;
fscanf(fin, "%d %d", &m, &n);
for(int i = n-m+1; i <= n; i++) // 对于f(n)/f(n-m)进行约去, 避免中间结果的溢出
result *= i;
result /= factorial(m);
fprintf(fout, "%d", result);
fclose(fin);
fclose(fout);
return 0;
}
(2)第一版P54 例题4-2 孪生素数
#include <cstdio>
#include <cmath>
#include <cassert>
int is_prime(int x)
// 判断x是否为素数, 若x是素数返回1否则返回0.
{
assert(x>=1);
if(x==1)return 0;
// 利用中间变量temp避免重复计算sqrt(x)降低循环效率
int i, temp = static_cast<int>(floor(sqrt(x)+0.5));
for(i = 2; i <= temp; i++)
if(x % i == 0)
return 0;
return 1;
}
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
int num, i;
fscanf(fin, "%d", &num);
for(i = num-2; i>=3; i--)
if(is_prime(i) && is_prime(i+2))
{
fprintf(fout, "%d %d", i, i+2);
break;
}
fclose(fin);
fclose(fout);
return 0;
}