• 【深入浅出程序设计竞赛(基础篇)第四章 算法从0开始】


    第四章 例题

    例4-1

    #include
    using namespace std;
    int main(){
        int L, i; cin >> L;
        for (i = 1; i <= L; i++) {
            cout << "Today, I ate " << i << " apple";
            if (i != 0 && i != 1) cout << "s";
            cout << "." << endl;
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    例4-2

    #include
    using namespace std;
    int main(){
        int n, tmp, minnum = 100000000;
        cin >> n;
        for (int i = 0; i < n; i++) {
            cin >> tmp;
            if (tmp < minnum) minnum = tmp;
        }
        cout << minnum << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    例4-3

    更简单的解法

    #include
    using namespace std;
    int main(){
        int n, k, i;
        int Asum = 0, Bsum = 0;
        scanf("%d%d", &n, &k);
        if (n < k) {
            Asum = 0;
        }else {
            Asum = (n / k + 1) * (n / k) / 2 * k;
        }
        Bsum = (n + 1) * n / 2 - Asum;
        printf("%.1f %.1f",  double(Asum) / (n / k), double(Bsum) / (n - n / k));
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    书上解法

    #include
    using namespace std;
    int main(){
        int n, k, i;
        int Asum = 0, Bsum = 0;
        scanf("%d%d", &n, &k);
        for (i = k; i <= n; i += k) {
            Asum += i;
        }
        Bsum = (1 + n) * n / 2 - Asum;
     printf("%.1f %.1f",  double(Asum) / (n / k), double(Bsum) / (n - n / k)); //%lf仅用于读入double类型变量而不用于输出
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    例4-4

    #include
    using namespace std;
    int main(){
        int a, days = 1;
        cin >> a;
        while(a > 1)
            days++, a /= 2;
        cout << days;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    例4-5

    #include
    #include
    #include
    using namespace std;
    int main(){
        int ans, guess;
        srand(time(0));
        ans = rand() % 100 + 1;
        cout << ans;
        do {
            cin >> guess;
            if (guess < ans) 
                cout << "Too small" << endl;
            if (guess > ans)
                cout << "Too large" << endl;
        }while(ans != guess);
        cout << "You are right!!!" << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    例4-6

    #include
    using namespace std;
    int main(){
        int cnt = 0, n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n - i + 1; j++) {
                printf("%02d", ++cnt);
            }
            printf("\n");
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    例4-7

    这道题书上的题解并不能解答洛谷P1009的题目,等后面学到第八章再来更新答案

    #include
    using namespace std;
    int main(){
        long long n, ans = 0;
        cin >> n;
        for(int i = 1; i <= n; i++){
            long long factor = 1;
            for(int j = 1; j <= i; j++){
                factor *= j;
            }
            ans += factor;
        }
        cout << ans << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    也可以采用递归

    #include
    using namespace std;
    
    long long calc(int n){
        if(n == 1)
            return 1;
        else
            return calc(n-1) * n;
    }
    
    int main(){
        long long n, ans = 1;
        cin >> n;
        for(int i = 2; i <= n; i++){
            ans += calc(i);
        }
        cout << ans << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    例4-8

    #include
    using namespace std;
    
    int main(){
        int n, x, ans = 0;
        cin >> n >> x;
        for(int i = 1; i <= n; i++){
            int tmp = i, num;
            while(tmp != 0){
                num = tmp % 10;
                if(num == x)
                    ans++;
                tmp /= 10;
            }
        }
        cout << ans;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    例4-9

    #include
    using namespace std;
    
    int main(){
        int k, ans = 0;
        cin >> k;
        for(double Sn = 0; Sn <= k; ans++, Sn += 1.0 / ans);
        cout << ans;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    例4-10

    书上解法

    #include
    using namespace std;
    
    int main(){
        int k, coin = 0, day = 0;
        cin >> k;
        for(int i = 1;; i++){
            for(int j = 1; j <= i; j++){
                coin += i; day++;
                if(day == k){
                    cout << coin << endl;
                    return 0;
                }
            }
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    我的解法

    #include
    using namespace std;
    
    int main(){
        int k, ans = 0, i;
        cin >> k;
        for(i = 1; i <=k; i++){
            ans += i * i; //加上当前天数的金币
            k -= i; //保证剩下还有天数
        }
        ans += i * k; //加上剩下天数的钱币
        cout << ans;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    例4-11

    解法一

    #include
    using namespace std;
    
    int main(){
        int n, s = 0;
        cin >> n;
        for(int i = 1; i <= n; i++){
            s += i;
        };
        cout << s;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    解法二

    #include
    using namespace std;
    
    int main(){
        int s = 0, i = 0, n;
        cin >> n;
        while(n--) s += ++i;
        cout << s;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    例4-12

    #include
    using namespace std;
    
    int main(){
        double n, s = 0;
        cin >> n;
        for(int i = 1; i <= n; i++){
            s += i * 0.1;
        };
        cout << s;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    错误代码,注意精度

    #include
    using namespace std;
    
    int main(){
        int n;
        double s = 0;
        cin >> n;
        for(double i = 0.1; i != n; i += 0.1){
            s += i; 
            // cout << s << endl;
        }
        cout << s;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    例4-13

    #include
    using namespace std;
    
    int main(){
        int L, load = 0, ans = 0;
        cin >> L;
        for(int i = 2; ; i++){
            int is_prime = 1;
            // for(int j = 2; j * j <= i; j++){ //正常写应该是j <= sqrt(i),改为乘法加快运算速度
                if(i % j == 0){
                    is_prime = 0;
                    break;
                }
            }
            if(!is_prime) continue;
            if(i + load > L) break;
            cout << i << endl;
            ans++; load += i;
        }
        cout << ans;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    例4-14

    解题思路:
    1、因为回文数的数量很少,所以先构造回文数
    题目数据范围:5≤a

    • 数据位数可以是1、2、3、4、5、6、7、8、9
    • 位数为1且>=5的回文数质数:5、7
    • 位数为2的回文数质数:11
    • 位数为4、6、8的回文数都是11的整数倍不是质数,不予考虑
    • 位数为3、5、7的回文数:自己构造
    • 位数为9的数只有一个100000000显然不满足条件,不予考虑

    2、再判断是否是质数
    3、如果符合条件则输出

    #include
    using namespace std;
    
    int is_prime(int x){
        if(x % 2 == 0) return 0; //偶数一定不是质数
        for(int i = 3; i * i <= x; i++){
            if(x % i == 0) return 0;
        }
        return 1;
    }
    
    int main(){
        int a, b;
        cin >> a >> b;
        //回文数奇数位为1时 只有 2 3 5 7满足是质数,本题范围>=5,所以只有5 7
        if(a <= 5 && b >= 5) cout << 5 << endl;
        if(a <= 7 && b >= 7) cout << 7 << endl;
        // 回文数位数为偶数时,只有11为质数,其他都是11的倍数,如1001、1221、345543
        if(a <= 11 && b >= 11) cout << 11 << endl;
    
        //3、5、7枚举
        //三位数的回文数
        for(int d1 = 1; d1 <= 9; d1 += 2){ //开头数字不能为0,偶数一定不是质数
            for(int d2 = 0; d2 <= 9; d2++){
                int num = 100 * d1 + 10  * d2 + d1;
                if(num < a) continue;
                if(num > b) return 0;
                if(is_prime(num)) cout << num << endl;
            }
        }
    
        //五位数的回文数
        for(int d1 = 1; d1 <= 9; d1 += 2){
            for(int d2 = 0; d2 <= 9; d2++){
                for(int d3 = 0; d3 <= 9; d3++){
                    int num = 10000 * d1 + 1000*d2 + 100 * d3 + 10 * d2 + d1;
                    if(num < a) continue;
                    if(num > b) return 0;
                    if(is_prime(num)) cout << num << endl;
                }
            }
        }
    
         //七位数的回文数
        for(int d1 = 1; d1 <= 9; d1 += 2){
            for(int d2 = 0; d2 <= 9; d2++){
                for(int d3 = 0; d3 <= 9; d3++){
                    for(int d4 = 0; d4 <= 9; d4++){
                        int num = 1000000 * d1 + 100000*d2 + 10000 * d3 + 1000 * d4 + 100 * d3 + 10 * d2 + d1;
                        if(num < a) continue;
                        if(num > b) return 0;
                        if(is_prime(num)) cout << num << endl;
                    }
                }
            }
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    第四章 课后习题

    4-1

    使用c++自带的库函数

    #include
    #include
    using namespace std;
    int main(){
        int a[5] = {11, 3, 5, 90, 20};
        sort(a, a+5);
        cout << a[4];
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    自己写排序算法,如冒泡排序
    做了两处优化:1、循环次数优化 2、flag标志减少排序次数

    #include
    using namespace std;
    int main(){
        int a[5] = {11, 3, 5, 90, 20}, temp, flag;
        for(int i = 0; i < 5 - 1; i++){
            for(int j = 0; j < 5 - 1 - i; j++){
                flag = 0;
                if(a[j] > a[j + 1]){
                    temp = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = temp;
                    flag = 1;
                }
            }
            if(!flag) break; //如果flag没有改变,则说明数据已经排好序,无需继续排序
        }
        for(int i = 0; i < 5; i++) cout << a[i] << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4-2

    等比数列求和公式s = a1 * (1 - q ^ n) / (1 - q)
    反推n = log(1 - (1 - q) / 2 * s) / log(q)
    题目中n全部都是整数,也就是说,宁可多走一步步,让实际路程>=要求路程
    因此在上式中,一旦n算出来是带小数的,就得把它进一位,因此再加一个ceil函数
    a1 = 2, q = 0.98,即n = ceil(log(1 - 0.01 * s) / log(0.98))

    #include
    #include
    using namespace std;
    int main(){
        float s, sum = 2;
        cin >> s;
        int ans;
        ans = ceil(log(1 - 0.01 * s) / log(0.98));
        cout << ans;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4-3

    巧妙之处在于可以用字符串接收数字会很方便反转,对对应位直接进行加减也就没有了前置0 问题了

    #include
    #include
    using namespace std;
    
    int main(){
        string a;
        cin >> a;
        long long ans = 0;
        if(a[0] == '-'){
            for(int i = a.length() - 1; i >= 1; i--){
                ans -= (a[i] - '0') * pow(10, i-1);
            }
        }else{
            for(int i = a.length() - 1; i >= 0; i--){
               ans += (a[i] - '0') * pow(10, i);
            }
        }
        cout << ans;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    4-4

    斐波那契数列

    解法一:递归
    但是洛谷超时

    #include
    using namespace std;
    
    float cum(int n){
        if(n == 0){
            return 0;
        }else if(n == 1 || n == 2){
            return 1;
        }
        else{
            return cum(n-1) + cum(n-2);
        }
    }
    
    int main(){
        int n;
        scanf("%d", &n);
        float ans = cum(n);
        printf("%.2f", ans);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    解法二:
    递推

    #include
    using namespace std;
    
    int main(){
        int n;
        scanf("%d", &n);
        double f[50] = {0, 1, 1};
        for(int i = 3; i <= n; i++){
            f[i] = f[i - 1] + f[i - 2];
        }
        printf("%.2lf", f[n]);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4-5

    #include
    using namespace std;
    
    int main(){
        int n;
        cin >> n;
        int temp, min = 1001, max = -1;
        for(int i = 0; i < n; i++){
            cin >> temp;
            if(temp < min) min = temp;
            if(temp > max) max = temp;
        }
        cout << max - min;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4-6

    #include
    using namespace std;
    
    int main(){
        int n;
        cin >> n;
        int f[n];
        for(int i = 0; i < n; i++){
            cin >> f[i];
        }
        int c = 1, ans = 1;
        for(int i = 0; i < n - 1; i++){
            if(f[i + 1] - f[i] == 1) c++;
            else c = 1;
            if(c > ans) ans = c;
        }
        cout << ans;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4-7

    唯一分解定理: 一个数能且只能分解为一组质数的乘积。
    可知,若输入的数满足题目条件,他就只能分解为两个质数的乘积。所以在比他小且大于1的自然数中,只有那两个数能整除它,之间不可能再有任何合数或质数能整除它了,因为最小的能整除它的合数已经是他本身了。

    #include
    using namespace std;
    
    int main(){
        int n;
        cin >> n;
        for(int i = 2; i < n; i ++){
            if(n % i == 0){
                cout << n / i;
                break;
            }
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4-8

    #include
    
    int main(){
        int n;
        scanf("%d", &n);
    
        int c = 1;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                printf("%02d", c);
                c++;
            }
            printf("\n");
        }
    
        printf("\n");
    
        c = 1;
         for(int i = 1; i <= n; i++){
            for(int k = 1; k <= 2 * n - 2 * i; k++){
                printf(" " );
            }
            for(int j = 1; j <= i; j++){
                printf("%02d", c);
                c++;
            }
            printf("\n");
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    4-9

    #include
    using namespace std;
    
    int main(){
        int n;
        cin >> n;
        int a[n];
        for(int i = 0; i < n; i++){
           cin >> a[i];
        }
        sort(a, a+n);
        double ans;
        for(int i = 1; i < n - 1; i++){
            ans += a[i];
        }
        printf("%.2lf", ans / (n - 2));
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4-10

    #include
    using namespace std;
    
    int main(){
        int n;
        cin >> n;
        int start = n / 364;
        if(start > 100) start = 100;
        for(int i = start; i >= 1; i--){
            int k = 1;
            while(k > 0){
                if((i + 3 * k) * 364 == n){
                    cout << i << endl;
                    cout << k << endl;
                    return 0;
                }
                else if((i + 3 * k) * 364 > n){
                    break;
                }
                k++;
            }
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    4-11

    #include
    using namespace std;
    
    int main(){
        int cost = 0, balance = 0, money = 0;
        for(int i = 1; i <= 12; i++){
            cin >> cost;    
            balance += 300 - cost;
            if(balance < 0){
                cout << -i;
                return 0;
            }
            else if(balance % 100 >= 0){
                money +=  balance - balance % 100;
                balance = balance % 100;
            }
        }
        cout << money * 1.2 + balance;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    搜索技巧+数学建模图片制作
    Java学习 --- 面向对象三大特征之封装
    秋招面试题系列- - -Java工程师(三)
    【ESD专题】案例 :结构设计导致的ESD问题
    我的四周年创作纪念日
    【高速PCB电路设计】8.DDR模块设计实战
    Jenkins 太老了 试试它?云原生 CI/CD Tekton
    2015年亚太杯APMCM数学建模大赛B题城市公共交通服务水平动态评价模型求解全过程文档及程序
    ip_vs 原理解析 (四)hook 后的开始 NF_INET_LOCAL_OUT
    如何快速确定论文的选题?
  • 原文地址:https://blog.csdn.net/qq_44948213/article/details/132304320