算法竞赛入门经典(刘汝佳)——代码笔记

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;
}




  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值