机试_4_数学问题

news2024/11/17 14:24:25

在机试中,我们经常会面对这样一类问题,它们并不涉及很深奥的算法和数据结构,而只与数理逻辑相关,将这类题目称为数学问题。

这类问题通常不需要用到特别高深的数学知识,而只需要掌握简单的数理逻辑知识。本文重点记录机试中常常涉及的一系列数学问题,以便很好地掌握计算机考研机试中涉及的数学问题的求解。

一、进制转换

三种题型:
1. 十进制转N进制(10 --> N)
2. M进制转10进制(M --> 10)
3. M进制转N进制(M --> N)

1、二进制数–北京邮电大学

描述:

大家都知道,数据在计算机里中存储是以二进制的形式存储的。 有一天,小明学了C语言之后,他想知道一个类型为unsigned int 类型的数字,存储在计算机中的二进制串是什么样子的。 你能帮帮小明吗?并且,小明不想要二进制串中前面的没有意义的0串,即要去掉前导0。

输入描述:

多行,每一行表示要求的数字

输出描述:

输出共T行。每行输出求得的二进制串。

示例1:

输入:

23
535
2624
56275
989835

输出:

10111
1000010111
101001000000
1101101111010011
11110001101010001011

题解:

分析:
十进制正数转二进制,使用"除2取余法"即可。

我们使用一个数组来存放 num % 2 的值,然后再将num / 2,以此循环,直至num为0。
最后逆序输出数组即可。
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

/**
 * 将整数转划为二进制
 * @param num
 */
void convertToBinary(int num);


/**
 * 二进制数--北京邮电大学
 * @return
 */
int main() {
    int num;
    while (cin >> num) {
        convertToBinary(num);
    }

    return 0;
}

void convertToBinary(int num) {
    vector<int> countVector;
    if (num == 0) {
        //特殊情况,num为0
        countVector.push_back(0);
    } else {
        while (num != 0) {
            countVector.push_back(num % 2);
            //右移1位相当于除2
            num = num >> 1;
        }
    }

    /*
     * 逆序输出
     */
    for (int i = countVector.size() - 1; i >= 0; --i) {
        cout << countVector[i];
    }
    cout << endl;
}

2、八进制–华中科技大学

描述:

输入一个整数,将其转换成八进制数输出。

输入描述:

输入包括一个整数N(0<=N<=100000)。

输出描述:

可能有多组测试数据,对于每组数据, 输出N的八进制表示数。

示例1

输入:

7
8
9

输出:

7
10
11

题解:

分析:
十进制正数转八进制,使用"除8取余法"即可。
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;


/**
 * 将十进制整数转化为n进制
 * @param num
 * @param n
 */
void convertTen2N(int num, int n);


/**
 * 八进制数--华中科技大学
 * @return
 */
int main() {
    int num;
    while (cin >> num) {
        //转八进制
        convertTen2N(num, 8);
    }

    return 0;
}

void convertTen2N(int num, int n) {
    vector<int> countVector;
    if (num == 0) {
        //特殊情况,num为0
        countVector.push_back(0);
    } else {
        while (num != 0) {
            countVector.push_back(num % n);
            num /= n;
        }
    }

    /*
     * 逆序输出
     */
    for (int i = countVector.size() - 1; i >= 0; --i) {
        cout << countVector[i];
    }
    cout << endl;
}

3、进制转换–北京大学

描述:

写出一个程序,接受一个十六进制的数值字符串,输出该数值的十进制字符串(注意可能存在的一个测试用例里的多组数据)。

输入描述:

输入一个十六进制的数值字符串。

输出描述:

输出该数值的十进制字符串。

示例1

输入:

0xA

输出:

10

题解:

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>

using namespace std;

/**
 * char转int
 * @param target
 * @return
 */
int char2Int(char target);

/**
 * 将m进制的num转化为十进制
 * @param num
 * @param m
 */
void convertM2Ten(string num, int m);

/**
 * 进制转换--北京大学
 * @return
 */
int main() {
    string hexNum;
    while (cin >> hexNum) {
        hexNum = hexNum.substr(2);
        //16进制转10进制
        convertM2Ten(hexNum, 16);
    }

    return 0;
}

int char2Int(char target) {
    if ('0' <= target && target <= '9') {
        //0~9直接减去字符0即可
        return target - '0';
    } else {
        //大于等于10,则先减去字符A(注意题目是大写还是小写),再加上10
        return target - 'A' + 10;
    }
}

void convertM2Ten(string num, int m) {
    int number = 0;

    /*
     * 解法1
     */
    for (int i = 0; i < num.size(); ++i) {
        number *= m;
        number += char2Int(num[i]);
    }

    /*
     * 解法2:利用基数乘以权重
     */
//    int x = 1;
//    for (int i = num.size() - 1; i >= 0; --i) {
//        number += char2Int(num[i]) * x;
//        x *= m;
//    }
    cout << number << endl;
}


4、进制转换2–清华大学

描述:

将M进制的数X转换为N进制的数输出。

输入描述:

输入的第一行包括两个整数:M和N(2<=M,N<=36)。
下面的一行输入一个数X,X是M进制的数,现在要求你将M进制的数X转换成N进制的数输出。

输出描述:

输出X的N进制表示的数。

示例1

输入:

10 2
11

输出:

1011

备注:

注意输入时如有字母,则字母为大写,输出时如有字母,则字母为小写。

题解:

分析:
上面的题都懂了之后,综合起来就是本题的解法了。
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

/**
 * char转int
 * @param target
 * @return
 */
int char2Int(char target);

/**
 * int转char
 * @param target
 * @return
 */
char int2Char(int target);

/**
 * 将m进制的num转化为十进制
 * @param num
 * @param m
 */
long long convertM2Ten(string num, int m);

/**
 * 将十进制的num转化为n进制
 * @param num
 * @param n
 */
void convertTen2N(long long num, int n);

/**
 * 进制转换2--清华大学
 * @return
 */
int main() {
    int m, n;
    while (cin >> m >> n) {
        string num;
        cin >> num;
        long long number = convertM2Ten(num, m);
        convertTen2N(number, n);
    }

    return 0;
}

long long convertM2Ten(string num, int m) {
    long long number = 0;
    for (int i = 0; i < num.size(); ++i) {
        number *= m;
        number += char2Int(num[i]);
    }
    return number;
}

void convertTen2N(long long num, int n) {
    vector<char> ans;
    if (num == 0) {
        //特殊情况
        ans.push_back('0');
    } else {
        while (num != 0) {
            ans.push_back(int2Char(num % n));
            num /= n;
        }
    }

    for (int i = ans.size() - 1; i >= 0; --i) {
        cout << ans[i];
    }
    cout << endl;
}

char int2Char(int target) {
    if (target < 10) {
        return target + '0';
    } else {
        //题目备注已经说明,输出为小写字母
        return target - 10 + 'a';
    }
}

int char2Int(char target) {
    if ('0' <= target && target <= '9') {
        //0~9直接减去字符0即可
        return target - '0';
    } else {
        //大于等于10,则先减去字符A(注意题目是大写还是小写),再加上10
        return target - 'A' + 10;
    }
}


二、GCD & LCM

1.最大公约数
最大公约数(Greatest Common Divisor,GCD)是指两个或多个整数共有约数中,最大的一个约数。
求最大公约数最常用的方法是欧几里得算法,又称辗转相除法。

若整数g为a,b(a和b不同时为0)的公约数,则g满足 a = g × l、b = g × m
其中,l,m为整数。同时,a又可由b表示为 a = b × k + n
其中,k为整数,r为α除以b后的余数。对以上三个公式做如下变形:
		g × l = g × m × k + r
		r = g × (l - m × k), (g ≠ 0)
由上式可知,a,b的公约数g可以整除a除以b后的余数r(记为a mod b)。即(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等。

这样,把求a,b的最大公约数转换成了求b,a mod b的最大公约数,问题不变而数据规模明显变小。
通过不断重复该过程,直到问题缩小成求某个非零数与零的最大公约数。
这样,该非零数即是所求。
2.最小公倍数
最小公倍数(Least Common Multiple,LCM)是指要两个或多个整数公有的倍数中,除0之外最小的那一个公倍数。
α,b两个数的最小公倍数为两数的乘积除以它们的最大公约数。

1、最大公约数–哈尔滨工业大学

描述:

输入两个正整数,求其最大公约数。

输入描述:

测试数据有多组,每组输入两个正整数。

输出描述:

对于每组输入,请输出其最大公约数。

示例1:

输入:

49 14

输出:

7

题解:

解法1:暴力枚举
假设两个数a、b,且a > b。
我们a开始,以此递减,若 a % i == 0 && b % i == 0,则此时的i即为最大公约数。
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>

using namespace std;

/**
 * 求x、y的最大公约数
 * @param x
 * @param y
 * @return
 */
int getGCD(int x, int y);

int getMax(int x, int y);

/**
 * 最大公约数--哈尔滨工业大学
 * @return
 */
int main() {
    int x, y;
    while (cin >> x >> y) {
        cout << getGCD(x, y) << endl;
    }

    return 0;
}

int getGCD(int x, int y) {
    int max = getMax(x, y);
    for (int i = max; i >= 0; --i) {
        if (x % i == 0 && y % i == 0) {
            return i;
        }
    }
    return -1;
}

int getMax(int x, int y) {
    return x >= y ? x : y;
}

解法2:辗转相除法(欧几里得算法)
假设求 GCD(3139, 2117)
1. 3139 % 2117 = 1022
2. 2117 % 1022 = 73
3. 1022 % 73 = 0

则,GCD(3139, 2117) = 73
即,73为3139和2117的最大公约数

至于代码,可以基于递归进行实现。
递归出口是GCD(x, y)中的y等于0。
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>

using namespace std;

/**
 * 求x、y的最大公约数--递归实现
 * @param x
 * @param y
 * @return
 */
int getGCD(int x, int y);


/**
 * 最大公约数--哈尔滨工业大学
 * @return
 */
int main() {
    int x, y;
    while (cin >> x >> y) {
        cout << getGCD(x, y) << endl;
    }

    return 0;
}

int getGCD(int x, int y) {
    //递归出口
    if (y == 0) {
        return x;
    }
    return getGCD(y, x % y);
}


2、最小公倍数–杭州电子科技

描述:

输入两个正整数,求其最小公倍数。

输入描述:

测试数据有多组,每组只有一行,包括两个不大于1000的正整数。

输出描述:

对于每组输入,请输出其最小公倍数,每个实例输出一行。

示例1:

输入:

49 14

输出:

7

题解:

解法1:暴力枚举
LCM(x, y)
从1 ~ (x*y)开始枚举,若满足 (i % x == 0 && i % y == 0),则i即可x、y的最小公倍数。
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>

using namespace std;

/**
 * 求x、y的最小公倍数
 * @param x
 * @param y
 * @return
 */
int getLCM(int x, int y);

/**
 * 最小公倍数--杭州电子科技大学
 * @return
 */
int main() {
    int x, y;
    while (cin >> x >> y) {
        cout << getLCM(x, y) << endl;
    }

    return 0;
}

int getLCM(int x, int y) {
    int max = x * y;
    for (int i = 1; i <= max; ++i) {
        if (i % x == 0 && i % y == 0) {
            return i;
        }
    }
    return -1;
}
解法2:数学公式
LCM(x, y) = (x * y) / GCD(x, y);
其中,GCD(x, y)表示x、y的最大公约数。
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>

using namespace std;

/**
 * 求x、y的最小公倍数
 * @param x
 * @param y
 * @return
 */
int getLCM(int x, int y);

/**
 * 求x、y的最大公约数--递归实现
 * @param x
 * @param y
 * @return
 */
int getGCD(int x, int y);

/**
 * 最小公倍数--杭州电子科技大学
 * @return
 */
int main() {
    int x, y;
    while (cin >> x >> y) {
        cout << getLCM(x, y) << endl;
    }

    return 0;
}

int getLCM(int x, int y) {
    return (x * y) / getGCD(x, y);
}

int getGCD(int x, int y) {
    //递归出口
    if (y == 0) {
        return x;
    }
    return getGCD(y, x % y);
}

三、质数

质数: 也称素数,是指只能被其自身和1整除的正整数。

如何判断一个数是否为素数呢?
可以用所有小于该数的正整数去试着整除该数,若存在某个数能够整除该数,则该数不是素数:若这些数都不能整除它,则该数为素数。
算法的时间复杂度为O(n)。

然而,并不用测试到 n-1,而只需测试到sqrt(n),即√n的整数即可.
	若到这个整数为止,所有正整数均不能整除n,则可以断定n为素数。
	若n不存在大于sqrt(n)的因数,则该做法显然正确:
如此一来,测试一个数是否是素数的复杂度就从O(n)降至了O(sqrt(n))。
分解质因数
素数的应用之一就是应用在分解质因数。
每个数都可以写成一个或几个质数相乘的形式,其中每个质数都是这个数的质因数。
例如:
30 = 2 * 3 * 5
120 = 2 * 2 * 2 * 3 * 5

1、素数判断–哈尔滨工业大学

描述

给定一个数n,要求判断其是否为素数(0,1,负数都是非素数)。

输入描述:

测试数据有多组,每组输入一个数n。

输出描述:

对于每组输入,若是素数则输出yes,否则输入no。

示例1

输入:

13

输出:

yes

题解:

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cmath>

using namespace std;

/**
 * 判断一个数是否为素数
 * @param num
 * @return
 */
bool isPrimeNum(int num);

/**
 * 素数判定--哈尔滨工业大学
 * @return
 */
int main() {
    int num;
    while (cin >> num) {
        if (isPrimeNum(num)) {
            cout << "yes" << endl;
        } else {
            cout << "no" << endl;
        }
    }

    return 0;
}


bool isPrimeNum(int num) {
    if (num <= 1) {
        return false;
    }
    //sqrt()比较耗时,所以提前定义一个变量进行赋值
    int bound = sqrt(num);
    for (int i = 2; i <= bound; ++i) {
        if (num % i == 0) {
            return false;
        }
    }
    return true;
}

2、素数–北京航空航天大学

描述

输入一个整数n(2<=n<=10000),要求输出所有从1到这个整数之间(不包括1和这个整数)个位为1的素数,如果没有则输出-1。

输入描述:

输入有多组数据。 每组一行,输入n。

输出描述:

输出所有从1到这个整数之间(不包括1和这个整数)个位为1的素数(素数之间用空格隔开,最后一个素数后面没有空格),如果没有则输出-1。

示例1

输入:

100

输出:

11 31 41 61 71

题解:

解法:素数筛法
算法思想:
找到一个素数,就将它的所有倍数均标记成非素数。这样一来,当遍历到一个数时,若它未被任何小于它的素数标记为非素数,则确定其为素数。

步骤如下:
从2到区间端点开始遍历,若当前整数(假设为A),没有因为一个小于A的素数的倍数而被标记为非素数时,则判断A为素数,同时标记A的整数倍为非素数。
继续遍历下一个数,以此循环,直到遍历完题设的区间。
此时,所有未被标记成非素数的数即为要求的素数。

解题思路:
在处理输入的数据之前,可以先利用素数筛法求出2到10000内的所有素数。
然后得到输入n之后,依次判断在1~n这个区间内的素数是否符合题目条件,若符合则输出盖素数,否则继续判断下一个素数,直至该区间内所有的素数都判断完为止。
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

const int MAX_NUM = 10001;

/**
 * 保存素数
 */
vector<int> primeNum;

/**
 * 标记素数
 */
bool isPrimeNum[MAX_NUM];

/**
 * 初始化 isPrimeNum[]数组
 */
void init();

/**
 * 素数--北京航空航天大学
 * @return
 */
int main() {
    init();
    int n;
    while (cin >> n) {
        bool isOutput = false;
        for (int i = 1; i < n; ++i) {
            /*
             * i % 10 == 1表示个位为1,且i为素数,则输出
             */
            if (i % 10 == 1 && isPrimeNum[i]) {
                isOutput = true;
                cout << i << " ";
            }
        }
        if (!isOutput) {
            cout << "-1";
        }
        cout << endl;
    }

    return 0;
}

void init() {
    //初始化
    for (int i = 0; i < MAX_NUM; ++i) {
        isPrimeNum[i] = true;
    }
    /*
     * 0、1都不是素数
     */
    isPrimeNum[0] = false;
    isPrimeNum[1] = false;
    //从2开始遍历
    for (int i = 2; i < MAX_NUM; ++i) {
        if (!isPrimeNum[i]) {
            //数字i为非素数,则直接跳过
            continue;
        } else {
            //数字i为素数
            primeNum.push_back(i);
            /*
             * 若 i * i > MAX_NUM,则不用再循环了
             */
            if (i > MAX_NUM / i) {
                continue;
            }
            /*
             * 素数的整数倍为非素数
             * 直接从 i * i 开始循环,减少重复的工作,同时j += i,以保证j是i的整数倍
             * 为何从i*i开始呢?
             * 因为,i*k(其中k<i)必定已经在求k的某个素因数(必定小于i)时被标记过了,即i*k同时也是k的素因数的倍数。
             * 举例,标记素数3的倍数是,3 * 2 = 6,已经在标记素数2的倍数时被标记了,因此我们直接从3 * 3 = 9开始标记
             */
            for (int j = i * i; j < MAX_NUM; j += i) {
                isPrimeNum[j] = false;
            }
        }
    }
}


3、质因数的个数–清华大学

描述:

求正整数N(N>1)的质因数的个数。 相同的质因数需要重复计算。如120 = 2 x 2 x 2 x 3 x 5,共有5个质因数。

输入描述:

可能有多组测试数据,每组测试数据的输入是一个正整数N,(1 < N < 10^9)。

输出描述:

对于每组数据,输出N的质因数的个数。

示例1

输入:

120

输出:

5

题解:

本题是将输入的整数进行分解素因数,并计算每个素因数对应的幂指数之和。

思路分析:
我们先用素数筛法,预先筛选出所有可能在题设所给的数据范围内出现德素数,然后接收程序的输入n,利用短除法求解,即从2开始依次遍历所有小于n的素数(记为A),并判断其是否为n的因数。
若是,则用 n = n / A,继续循环。
若否,则继续循环。

算法实现:
1. 利用素数筛法筛选出[0, MAX_NUM]内的所有素数。
   注:MAX_NUM = sqrt(数据规模)即可,并不需要等于数据规模。
   令sqrt(n)为x,因为一个整数n,之多只会存在一个大于x的素因数(原因:两个大于x的数相乘必会大于n)。
   因此,将所有小于x的素因数从n去除,剩余部分必为大于x的素因数,且若存在大于x的素因数,其幂指数必为1。
2. 出入n
3. 从2开始测试素数(记为A)能否整除n。若能,则表明A是n的一个素因数。
4. 循环3,直到不能在被整除为止,同时统计其幂指数。
5. 遍历完预处理出来的素数后,
   若n为1,则表明n的所有素因数全部被分解出来。
   若n不为1,则表明n存在一个大于MAX_NUM的因子,该因子必为其素因子,且幂指数必然为1。
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

const int MAX_NUM = 4e4;

/**
 * 保存素数
 */
vector<int> primeNum;

/**
 * 标记素数
 */
bool isPrimeNum[MAX_NUM];

/**
 * 初始化 isPrimeNum[]数组
 */
void init();

/**
 * 质因数的个数--清华大学
 * @return
 */
int main() {
    init();
    int n;
    while (cin >> n) {
        int count = 0;
        for (int i = 0; i < primeNum.size() && primeNum[i] < n; ++i) {
            int factor = primeNum[i];
            //n能整除质因数
            while (n % factor == 0) {
                n /= factor;
                count++;
            }
        }
        //还存在一个大于sqrt(n)的质因数
        if (n > 1) {
            count++;
        }
        cout << count << endl;
    }

    return 0;
}

void init() {
    //初始化
    for (int i = 0; i < MAX_NUM; ++i) {
        isPrimeNum[i] = true;
    }
    /*
     * 0、1都不是素数
     */
    isPrimeNum[0] = false;
    isPrimeNum[1] = false;
    //从2开始遍历
    for (int i = 2; i < MAX_NUM; ++i) {
        if (!isPrimeNum[i]) {
            //数字i为非素数,则直接跳过
            continue;
        } else {
            //数字i为素数
            primeNum.push_back(i);
            /*
             * 若 i * i > MAX_NUM,则不用再循环了
             */
            if (i > MAX_NUM / i) {
                continue;
            }
            /*
             * 素数的整数倍为非素数
             * 直接从 i * i 开始循环,减少重复的工作,同时j += i,以保证j是i的整数倍
             * 为何从i*i开始呢?
             * 因为,i*k(其中k<i)必定已经在求k的某个素因数(必定小于i)时被标记过了,即i*k同时也是k的素因数的倍数。
             * 举例,标记素数3的倍数是,3 * 2 = 6,已经在标记素数2的倍数时被标记了,因此我们直接从3 * 3 = 9开始标记
             */
            for (int j = i * i; j < MAX_NUM; j += i) {
                isPrimeNum[j] = false;
            }
        }
    }
}

四、快速幂

快速幂:指快速求得a的b次方的方法。

在这里插入图片描述


1、人见人爱的A^B

描述

求AB的最后三位数表示的整数。说明:AB的含义是“A的B次方”。

输入描述:

输入数据包含多个测试实例,每个实例占一行,由两个正整数A和B组成(1 <= A,B <= 10000)。
如果A=0,B=0,则表示输入数据的结束,不做处理。

输出描述:

对于每个测试实例,请输出A^B的最后三位表示的整数,每个输出占一行。

示例1

输入:

2 3
12 6
6789 10000
0 0

输出:

8
984
1

题解:

本题的一个小坑,就是求一个数的后三位数。

最简单的方法:该数对1000取模即可。
但是在本例中,是否可以先求得A^B的具体数字后再求其后三位数呢?
显然,不行。

按照题面给出的输入规模,A^B至多可以达到10000的10000次方,这么庞大的数字是不容易存储的,但A^B的后三位数其实只与A的后三位数和B有关。

由于题目要求的只是结果的后三位数,因此在计算该结果的过程中产生的中间值也只需保存其后三位数即可。即在利用快速幂求A^B的计算过程中,只需不断地将中间结果对1000取模。
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>

using namespace std;

const int MOD = 1000;

/**
 * 快速幂求a^b
 * @param a
 * @param b
 * @return
 */
int quickPower(int a, int b);

/**
 * 人见人爱的A^B--杭州电子科技大学
 * @return
 */
int main() {
    int a, b;
    while (cin >> a >> b) {
        if (a == 0 && b == 0) {
            break;
        }
        cout << quickPower(a, b) << endl;
    }

    return 0;
}

int quickPower(int a, int b) {
    int ans = 1;
    while (b != 0) {
        if (b % 2 == 1) {
            ans *= a;
            //求后三位数
            ans %= MOD;
        }
        b = b >> 1;
        //a不断平方
        a *= a;
        //求后三位数
        a %= MOD;
    }
    return ans;
}

五、矩阵与矩阵快速幂

1. 矩阵
数学问题中另外一个常考的知识点是矩阵。
考查的内容不难,一般只考查矩阵的基本运算,如矩阵加法、矩阵乘法、矩阵转置等。
通常,可用一个二维数组来模拟矩阵。

2. 矩阵快速幂
类似于普通快速幂,矩阵的快速幂就是高效求矩阵多幂次的方法,其思想和普通快速幂的思想相同。
唯一不同的地方在于,对数字的快速幂而言,其初始值是1;而对于矩阵快速幂而言,其初始值是单位矩阵。
/**
 * 矩阵操作,包括
 * 1.矩阵加法(减法同理)
 * 2.矩阵乘法
 * 3.矩阵转置
 * 4.矩阵求幂
 */
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>

using namespace std;

/**
 * 矩阵维数
 */
const int DIMENSION = 3;

/**
 * 矩阵
 */
struct Matrix {
    int row;    //矩阵的行
    int col;    //矩阵的列
    int matrix[DIMENSION][DIMENSION];     //二维数组模拟矩阵
    //构造函数
    Matrix(int row, int col) {
        this->row = row;
        this->col = col;
    }
};

/**
 * 矩阵加法
 * @param x
 * @param y
 * @return
 */
Matrix add(Matrix x, Matrix y);

/**
 * 矩阵乘法
 * @param x
 * @param y
 * @return
 */
Matrix multiply(Matrix x, Matrix y);

/**
 * 矩阵转置
 * @param x
 * @return
 */
Matrix transpose(Matrix x);

/**
 * 矩阵求幂
 * @param x
 * @return
 */
Matrix quickPower(Matrix x, int n);

/**
 * 打印矩阵
 * @param x
 */
void printMatrix(Matrix x);

/**
 * 矩阵操作
 * @return
 */
int main() {
    /*
     * 自行测试矩阵操作
     */
    return 0;
}

Matrix add(Matrix x, Matrix y) {
    Matrix ans = Matrix(x.row, x.col);
    for (int i = 0; i < ans.row; ++i) {
        for (int j = 0; j < ans.col; ++j) {
            //对应位置相加即可
            ans.matrix[i][j] = x.matrix[i][j] + y.matrix[i][j];
        }
    }
    return ans;
}

Matrix multiply(Matrix x, Matrix y) {
    //矩阵乘法结果是x的行和y的列
    Matrix ans(x.row, y.col);
    for (int i = 0; i < ans.row; ++i) {
        for (int j = 0; j < ans.col; ++j) {
            //先初始化为0
            ans.matrix[i][j] = 0;
            /*
             * 根据矩阵相乘的规则
             * matrix[i][j] = x的第i行与y的第j列对应的乘积和
             */
            for (int k = 0; k < x.col; ++k) {
                ans.matrix[i][j] += x.matrix[i][k] * y.matrix[k][j];
            }
        }
    }
    return ans;
}

void printMatrix(Matrix x) {
    //注:特别注意题目明确的输出格式
    for (int i = 0; i < x.row; ++i) {
        for (int j = 0; j < x.col; ++j) {
            if (j == 0) {
                //第一列不带空格
                cout << x.matrix[i][j];
            } else {
                //非第一列带前置空格
                cout << " " << x.matrix[i][j];
            }
        }
        cout << endl;
    }
}

Matrix transpose(Matrix x) {
    Matrix ans = Matrix(x.col, x.row);
    for (int i = 0; i < x.row; ++i) {
        for (int j = 0; j < x.col; ++j) {
            ans.matrix[i][j] = x.matrix[j][i];
        }
    }
    return ans;
}

Matrix quickPower(Matrix x, int n) {
    Matrix ans = Matrix(x.row, x.col);
    //初始化为单位阵
    for (int i = 0; i < ans.row; ++i) {
        for (int j = 0; j < ans.col; ++j) {
            if (i == j) {
                ans.matrix[i][j] = 1;
            } else {
                ans.matrix[i][j] = 0;
            }
        }
    }

    /*
     * 求快速幂的方法
     */
    while (n != 0) {
        if (n % 2 == 1) {
            ans = multiply(ans, x);
        }
        n = n >> 1;
        x = multiply(x, x);
    }
    return ans;
}

1、计算两个矩阵的乘积–哈尔滨工业大学

描述

计算两个矩阵的乘积,第一个是2 x 3,第二个是3 x 2。

输入描述:

输入为两个矩阵,其中一个为2 x 3的矩阵,另一个为3 x 2的矩阵。

输出描述:

一个2 x 2的矩阵(每一个数字后都跟一个空格)。

示例1

输入:

1 2 3
3 4 5
6 7
8 9
10 11

输出:

52 58
100 112

题解:

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>

using namespace std;

/**
 * 矩阵维数
 */
const int DIMENSION = 3;

/**
 * 矩阵
 */
struct Matrix {
    int row;    //矩阵的行
    int col;    //矩阵的列
    int matrix[DIMENSION][DIMENSION];     //二维数组模拟矩阵

    //构造函数
    Matrix(int row, int col) {
        this->row = row;
        this->col = col;
    }
};

/**
 * 矩阵乘法
 * @param x
 * @param y
 * @return
 */
Matrix multiply(Matrix x, Matrix y);

/**
 * 打印矩阵
 * @param x
 */
void printMatrix(Matrix x);

/**
 * 计算两个矩阵的乘积--哈尔滨工业大学
 * @return
 */
int main() {
    Matrix x = Matrix(2, 3);
    Matrix y = Matrix(3, 2);
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 3; ++j) {
            cin >> x.matrix[i][j];
        }
    }
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 2; ++j) {
            cin >> y.matrix[i][j];
        }
    }
    Matrix ans = multiply(x,y);
    printMatrix(ans);

    return 0;
}

Matrix multiply(Matrix x, Matrix y) {
    //矩阵乘法结果是x的行和y的列
    Matrix ans(x.row,y.col);
    for (int i = 0; i < ans.row; ++i) {
        for (int j = 0; j < ans.col; ++j) {
            //先初始化为0
            ans.matrix[i][j] = 0;
            /*
             * 根据矩阵相乘的规则
             * matrix[i][j] = x的第i行与y的第j列对应的乘积和
             */
            for (int k = 0; k < x.col; ++k) {
                ans.matrix[i][j] += x.matrix[i][k] * y.matrix[k][j];
            }
        }
    }
    return ans;
}

void printMatrix(Matrix x) {
    for (int i = 0; i < x.row; ++i) {
        for (int j = 0; j < x.col; ++j) {
            cout << x.matrix[i][j] << " ";
        }
        cout << endl;
    }
}


2、矩阵幂–北京邮电大学

描述

给定一个n*n的矩阵,求该矩阵的k次幂,即P^k。

输入描述:

第一行:两个整数n(2<=n<=10)、k(1<=k<=5),两个数字之间用一个空格隔开,含义如上所示。 接下来有n行,每行n个正整数,其中,第i行第j个整数表示矩阵中第i行第j列的矩阵元素Pij且(0<=Pij<=10)。另外,数据保证最后结果不会超过10^8。

输出描述:

对于每组测试数据,输出其结果。格式为: n行n列个整数,每行数之间用空格隔开,注意,每行最后一个数后面不应该有多余的空格。

示例1

输入:

2 2
9 8
9 3
3 3
4 8 4
9 3 0
3 5 7
5 2
4 0 3 0 1
0 0 5 8 5
8 9 8 5 3
9 6 1 7 8
7 2 5 7 3

输出:

153 96
108 81
1216 1248 708
1089 927 504
1161 1151 739
47 29 41 22 16
147 103 73 116 94
162 108 153 168 126
163 67 112 158 122
152 93 93 111 97

题解:

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>

using namespace std;

/**
 * 矩阵维数
 */
const int DIMENSION = 10;

/**
 * 矩阵
 */
struct Matrix {
    int row;    //矩阵的行
    int col;    //矩阵的列
    int matrix[DIMENSION][DIMENSION];     //二维数组模拟矩阵

    //构造函数
    Matrix(int row, int col) {
        this->row = row;
        this->col = col;
    }
};

/**
 * 矩阵乘法
 * @param x
 * @param y
 * @return
 */
Matrix multiply(Matrix x, Matrix y);

/**
 * 矩阵求幂
 * @param x
 * @return
 */
Matrix quickPower(Matrix x, int n);

/**
 * 打印矩阵
 * @param x
 */
void printMatrix(Matrix x);


/**
 * 矩阵幂--北京邮电大学
 * @return
 */
int main() {
    int n;
    int k;
    while (cin >> n >> k) {
        Matrix x = Matrix(n, n);
        for (int i = 0; i < x.row; ++i) {
            for (int j = 0; j < x.col; ++j) {
                cin >> x.matrix[i][j];
            }
        }
        Matrix ans = quickPower(x, k);
        printMatrix(ans);
    }
    return 0;
}

Matrix multiply(Matrix x, Matrix y) {
    //矩阵乘法结果是x的行和y的列
    Matrix ans(x.row, y.col);
    for (int i = 0; i < ans.row; ++i) {
        for (int j = 0; j < ans.col; ++j) {
            //先初始化为0
            ans.matrix[i][j] = 0;
            /*
             * 根据矩阵相乘的规则
             * matrix[i][j] = x的第i行与y的第j列对应的乘积和
             */
            for (int k = 0; k < x.col; ++k) {
                ans.matrix[i][j] += x.matrix[i][k] * y.matrix[k][j];
            }
        }
    }
    return ans;
}

void printMatrix(Matrix x) {
    //注意题目明确的输出格式
    for (int i = 0; i < x.row; ++i) {
        for (int j = 0; j < x.col; ++j) {
            if (j == 0) {
                //第一列不带空格
                cout << x.matrix[i][j];
            } else {
                //非第一列带前置空格
                cout << " " << x.matrix[i][j];
            }
        }
        cout << endl;
    }
}

Matrix quickPower(Matrix x, int n) {
    Matrix ans = Matrix(x.row, x.col);
    //初始化为单位阵
    for (int i = 0; i < ans.row; ++i) {
        for (int j = 0; j < ans.col; ++j) {
            if (i == j) {
                ans.matrix[i][j] = 1;
            } else {
                ans.matrix[i][j] = 0;
            }
        }
    }

    /*
     * 求快速幂的方法
     */
    while (n != 0) {
        if (n % 2 == 1) {
            ans = multiply(ans, x);
        }
        n = n >> 1;
        x = multiply(x, x);
    }

    return ans;
}

六、高精度整数

最大的整型long long的范围是[-9223372036854775808, 9223372036854775807],即使是无符号位的 unsigned long long 最大值也只是扩大一倍。

在某些例子中,可以利用各种技巧回避了直接保存这种整数。但在有些问题中,不得不保存并处理数值巨大的整数。

那么该如何处理呢?这就是本节要讨论的内容——高精度整数(大整数)。

若机试允许使用Java的UU,直接跳过即可,因为Java类库中内置了BigInteger类,了解其用法然后尝试解题即可。

若机试允许使用Python的UU,直接无视即可,因为Python中整型不限制长度。

若机试只允许使用C\C++的UU,只能自定义结构体或者类来模拟大整数。

篇幅所限,另写博客记录。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/339428.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决访问GitHub时出现的“您的连接不是私密连接”的问题!

Content问题描述解决办法问题描述 访问github出现您的连接不是私密连接问题&#xff0c;无法正常访问&#xff0c;如下图所示&#xff1a; 解决办法 修改hosts文件。hosts文件位于&#xff1a;C:\Windows\System32\drivers\etc\hosts 首先在https://www.ipaddress.com/查找两…

Linux之case语句和循环语句

一、case语句1.case语句的结构case语句主要适用于以下情况&#xff1a;某个变量存在多种取值&#xff0c;需要对其中的每一种取值分别执行不同的命令序列。这种情况与多分支的if语句非常相似&#xff0c;只不过if语句需要判断多个不同的条件&#xff0c;而case语句只是判断一个…

Linux高级命令之查找文件命令

查找文件命令学习目标能够说出查找文件使用的命令1. find命令及选项的使用命令说明find在指定目录下查找文件(包括目录)find命令选项:选项说明-name根据文件名(包括目录名)字查找find命令及选项的效果图:2. find命令结合通配符的使用通配符:是一种特殊语句&#xff0c;主要有星…

Linux中几个在终端中有趣的命令

uhh…最近我不知道该更新些什么&#xff0c;所以就更新Linux几个很有趣的命令 文章目录前言1.命令&#xff1a;sl安装 sl输出2. 命令&#xff1a;telnet命令&#xff1a;fortune安装fortune4.命令&#xff1a;rev&#xff08;反转&#xff09;安装rev5. 命令&#xff1a;factor…

第二章 Opencv图像处理基本操作

目录1.读取图像1-1.imread()方法2.显示图像2-1.imshow()方法2-2.waitKey()方法2-3.destroyAllWindows()方法2-4.小总结3.保存图像3-1.imwrite()方法4.查看图像属性4-1.常见的三个图像属性1.读取图像 要对一幅图像进行处理&#xff0c;第一件事就是要读取这幅图像。 1-1.imread(…

Vue驼峰与短横线分割命名中有哪些坑

目录 0.前言 驼峰和短横线分割命名注意事项 组件注册命名 父子组件数据传递时命名 父子组件函数传递 0.前言 Vue驼峰命名法指的是将变量以驼峰形式命名&#xff0c;例如 userName、userId 等&#xff0c;而短横线分隔符法则指的是用短横线分隔变量名&#xff0c;例如 user…

Python 高级编程之生成器与协程进阶(五)

文章目录一、概述二、生成器1&#xff09;生成器和迭代器的区别2&#xff09;生成器创建方式1、通过生成器函数创建2、通过生成器表达式创建3&#xff09;生成器表达式4&#xff09;yield关键字5&#xff09;生成器函数6&#xff09;return 和 yield 异同7&#xff09;yield的使…

RocketMQ底层源码解——事务消息的实现

1. 简介 RocketMQ自身实现了事务消息&#xff0c;可以通过这个机制来实现一些对数据一致性有强需求的场景&#xff0c;保证上下游数据的一致性。 以电商交易场景为例&#xff0c;用户支付订单这一核心操作的同时会涉及到下游物流发货、积分变更、购物车状态清空等多个子系统…

Linux高级命令之压缩和解压缩命令

压缩和解压缩命令学习目标能够使用tar命令完成文件的压缩和解压缩1. 压缩格式的介绍Linux默认支持的压缩格式:.gz.bz2.zip说明:.gz和.bz2的压缩包需要使用tar命令来压缩和解压缩.zip的压缩包需要使用zip命令来压缩&#xff0c;使用unzip命令来解压缩压缩目的:节省磁盘空间2. ta…

如何在VMware虚拟机上安装运行Mac OS系统(详细图文教程)

一、安装前准备 虚拟机运行软件&#xff1a;VMware Workstation Pro&#xff0c;版本&#xff1a;16.0.0 。VMware Mac OS支持套件&#xff1a;Unlocker。Mac OS系统镜像。 如果VMware 在没有安装Unlocker的情况下启动&#xff0c;在选择客户机操作系统时没有支持Mac OS的选项…

Mock.js初步使用(浏览器端)

Mock.js&#xff1a;生成随机数据&#xff0c;拦截 Ajax 请求。官方地址&#xff1a;http://mockjs.com/第一个demodemo.html<!DOCTYPE html> <html> <head><meta charset"utf-8"><title>mockjs demo</title> </head> <…

STM32单片机OLED显示

OLED接口电路STM32单片机OLED显示程序源代码#include "sys.h"#define OLED_RST_Clr() PCout(13)0 //RST#define OLED_RST_Set() PCout(13)1 //RST#define OLED_RS_Clr() PBout(4)0 //DC#define OLED_RS_Set() PBout(4)1 //DC#define OLED_SCLK_Clr()PCout(15)0 //SCL…

详解Python文件pyinstaller打包

本文python文件打包用到的是pyinstaller库并且以如下格式的文件为例 其中bird.py用到了images文件夹当中的png pyinstaller有两种打包方式: 方法1:文件夹模式 onedir 在终端用命令 pyinstaller -D flappybird.py执行完后文件格式如下 可以看到多了.idea,pycache,build,dis…

Linux系列 备份与分享文档

作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.备份与分享文档 1.使用压缩和解压缩工具 &#xff08;1&…

Java零基础教程——数据类型

目录数据类型数据类型的分类运算符算术运算符符号做连接符的识别自增、自减运算符赋值运算符关系运算符逻辑运算符短路逻辑运算符三元运算符运算符优先级数据类型 数据类型的分类 引用数据类型&#xff08;除基本数据类型之外的&#xff0c;如String &#xff09; 基本数据类…

【STM32】【HAL库】遥控关灯2 分机

相关连接 【STM32】【HAL库】遥控关灯0 概述 【STM32】【HAL库】遥控关灯1主机 【STM32】【HAL库】遥控关灯2 分机 【STM32】【HAL库】遥控关灯3 遥控器 需求 接收RF433和红外信号,根据信号内容控制舵机 硬件设计 主控采用stm32F103c6 STM32 433接收 其他接口 软件设计 接…

[SSD固态硬盘技术 14] GC垃圾回收太重要了

今天介绍臭名昭著的垃圾收集 过程(或“GC”),maybe 这是对JAVA 工程师而言。当遇到GC导致速度降低时候, 他们真的想跳脚。 我想到我的小孩打疫苗,哭的哇哇叫, 在他的眼里疫苗应该也是讨厌的吧, 但事实真的如此吗? 但首先,让我们考虑一下如果根本没有 GC,闪存系统会发…

【Shell1】shell语法,ssh/build/scp/upgrade,环境变量,自动升级bmc,bmc_wtd,

文章目录1.shell语法&#xff1a;Shell是用C语言编写的程序&#xff0c;它是用户使用Linux的桥梁&#xff0c;硬件>内核(os)>shell>文件系统1.1 变量&#xff1a;readonly定义只读变量&#xff0c;unset删除变量1.2 函数&#xff1a;shell脚本传递的参数中包含空格&am…

微信小程序 学生选课系统--nodejs+vue

系统分为学生和管理员&#xff0c;教师三个角色 学生小程序端的主要功能有&#xff1a; 1.用户注册和登陆系统 2.查看选课介绍信息 3.查看查看课程分类 4.查看课程详情&#xff0c;在线选课&#xff0c;提交选课信息 5.在线搜索课程信息 6.用户个人中心修改个人资料 7.用户查看…

数据中心的 TCP-Delay ACK 与 RTO, RACK

TCP 对 RTO 有个最小值限制&#xff0c;一般限制为 MIN_RTO 200ms。之所以有这个限制&#xff0c;在于要适应 Delay ACK&#xff0c;而 Delay ACK 的意义&#xff0c;不多说&#xff0c;摘自 RFC1122&#xff1a; MIN_RTO 应该足够大&#xff0c;以覆盖 Delay ACK 的影响&…