机试_1_暴力求解

一、枚举

判断是否可以使用枚举:分析数据量。
若时间限制在1000ms的情况下,大约可以进行10⁷的运算。

复杂度数据量
O(n!)10
O(2ⁿ)20
O(n³)200
O(n²)3000
O(nlogn)10⁶
O(n)10⁷
O(√10)10¹⁴
O(logn)>10²⁰

在这里插入图片描述


1 abc–清华大学

描述

设a、b、c均是0到9之间的数字,abc、bcc是两个三位数,且有:abc+bcc=532。求满足条件的所有a、b、c的值。

输入描述:

题目没有任何输入。

输出描述:

请输出所有满足题目条件的a、b、c的值。 a、b、c之间用空格隔开。 每个输出占一行。

示例1

输入:


输出:


题解:

分析:
abc和bcc是两个三位数,由乘法分配律可知
abc = a*100 + b*10 + c
bcc = b*100 + c*10 + c = b*100 + 11*c
abc + bcc = a*100 + b*110 + c*12
#include <iostream>
#include <cstdio>
using namespace std;

int main() {
    for (int a = 0; a <= 9; ++a) {
        for (int b = 0; b <= 9; ++b) {
            for (int c = 0; c <= 9; ++c) {
                if (a*100 + b*110 + c*12 == 532) {
                    cout << a << " " << b << " " << c << endl;
                }
            }
        }
    }
    return 0;
}

2 反序数–清华大学

描述:

设N是一个四位数,它的9倍恰好是其反序数(例如:1234的反序数是4321)
求N的值

输入描述:

程序无任何输入数据。

输出描述:

输出题目要求的四位数,如果结果有多组,则每组结果之间以回车隔开。

示例1

输入:

输出:

题解:

#include <iostream>
#include <cstdio>

using namespace std;

/*
 * 反序数--清华大学
 */
int main() {
    int num = 0;
    int reverseNum = 0;
    for (int a = 0; a <= 9; ++a) {
        for (int b = 0; b <= 9; ++b) {
            for (int c = 0; c <= 9; ++c) {
                for (int d = 0; d <= 9; ++d) {
                    num = a * 1000 + b * 100 + c * 10 + d;
                    reverseNum = d * 1000 + c * 100 + b * 10 + a;
                    //0XXX不是四位数
                    if (a != 0 && d != 0) {
                        if (9 * num == reverseNum) {
                            cout << a << b << c << d << endl;
                        }
                    }
                }
            }
        }
    }

    return 0;
}
#include <iostream>
#include <cstdio>

using namespace std;

/**
 * 获取num的反序数
 * @param num 
 * @return 
 */
int getReverseNumber(int num) {
    int reverseNumber = 0;
    while (num != 0) {
        reverseNumber *= 10;
        reverseNumber += num % 10;
        num /= 10;
    }
    return reverseNumber;
}

/*
 * 反序数--清华大学
 */
int main() {
    /*
     * 1111*9=9999,所以i循环到1111即可
     */
    for (int i = 1000; i <= 1111; ++i) {
        if (9 * i == getReverseNumber(i)) {
            cout << i << endl;
        }
    }

    return 0;
}

3 对称平方数–清华大学

描述

打印所有不超过256,其平方具有对称性质的数。如2,11就是这样的数,因为22=4,1111=121。

输入描述:

无任何输入数据

输出描述:

输出具有题目要求的性质的数。如果输出数据不止一组,各组数据之间以回车隔开。

示例1

输入:

输出:

题解:

#include <iostream>
#include <cstdio>

using namespace std;

/**
 * 获取num的反序数
 * @param num
 * @return
 */
int getReverseNumber(int num) {
    int reverseNumber = 0;
    while (num != 0) {
        reverseNumber *= 10;
        reverseNumber += num % 10;
        num /= 10;
    }
    return reverseNumber;
}

/**
 * KY267 对称平方数--清华大学
 * @return
 */
int main() {
    /*
     * 判断某个数num,其完全平方数是否为对称数
     * 即 num*num = num*num的反序数
     */
    for (int num = 0; num <= 256; ++num) {
        if (num * num == getReverseNumber(num * num)) {
            cout << num << endl;
        }
    }

    return 0;
}

二、模拟

  1. 图形排版
  2. 日期问题
  3. 其他模拟

1 输出梯形–清华大学

描述:

输入一个高度h,输出一个高为h,上底边为h的梯形。

输入描述:

一个整数h(1<=h<=1000)。

输出描述:

h所对应的梯形。

样例

输入:

4

样例输出:

      ****    
    ******  
  ******** 
**********

题解:

此题只需要按几何的方法画出梯形,然后找到行和列之间的关系即可。

在这里插入图片描述

#include <iostream>
#include <cstdio>
using namespace std;

/**
 * 输出梯形--清华大学
 * @return
 */
int main() {
    //用户出入h
    int h;
    while (cin >> h) {
        //行
        int row = h;
        //列
        int col = h + 2 * (h - 1);

        /*
         * 解法1
         */
        for (int i = 0; i < row; ++i) {
            //打印空格
            for (int j = 0; j < col - h - 2 * i; ++j) {
                cout << " ";
            }

            //打印 *
            for (int k = 0; k < h + 2 * i; ++k) {
                cout << "*";
            }
            //打印换行
            cout << endl;
        }

        /*
         * 解法2
         */
        for (int i = 0; i < row; ++i) {
            for (int j = 0; j < col; ++j) {
                if (j < col - h - 2 * i) {
                    cout << " ";
                } else {
                    cout << "*";
                }
            }
            cout << endl;
        }
    }
    return 0;
}

2 叠筐–杭州电子科技大学

描述:

现在给你两种颜色的箩筐,需要的时候,就把一个个大小差一圈的筐叠上去,使得从上往下看时,边筐花色交错。这个工作现在要让计算机来完成,得看你的了。

输入描述:

输入是一个个的三元组,分别是,外筐尺寸n(n为满足0<n<80的奇整数),中心花色字符,外筐花色字符,后二者都为ASCII可见字符;

输出描述:

输出叠在一起的筐图案,中心花色与外筐花色字符从内层起交错相叠,多筐相叠时,最外筐的角总是被打磨掉。叠筐与叠筐之间应有一行间隔。

示例:

输入:

11 B A
5 @ W

输出:

 AAAAAAAAA
ABBBBBBBBBA
ABAAAAAAABA
ABABBBBBABA
ABABAAABABA
ABABABABABA
ABABAAABABA
ABABBBBBABA
ABAAAAAAABA
ABBBBBBBBBA
 AAAAAAAAA

 @@@
@WWW@
@W@W@
@WWW@
 @@@

题解:

这道题属实是有点难,思考了很久没什么思路,最后看了教程才有有点想法。

分析:
1、先将4个角补上,成为一个正方形。
2、从最外圈的正方形向内圈的正方形逐步构造。
3、以正方形的左上角坐标与右下角坐标来表示该圈。
4、为每个圈填充中心字符和外筐字符。
5、确定每个圈的边长,即填充字符的个数
6、构造完成后剔除4个角。

在这里插入图片描述

#include <iostream>
#include <cstdio>

using namespace std;

const int MAX_NUM = 80;

/**
 * 叠筐--杭州电子科技大学
 * @return
 */
int main() {
    //二维矩阵存放字符
    char matrix[MAX_NUM][MAX_NUM];
    //外圈边长
    int n;
    //中心字符
    char centerChar;
    //外圈字符
    char outsideChar;

    //第一个案列
    bool firstCase = true;

    while (cin >> n >> centerChar >> outsideChar) {
        //每个叠筐间输出空行
        if (firstCase) {
            //第一个叠筐不输出空行
            firstCase = false;
        } else {
            //非第一个叠筐输出空行
            cout << endl;
        }

        //(i, i)表示每个圈最左上角坐标
        for (int i = 0; i <= n / 2; ++i) {
            //(j, j)表示每个圈最右下角坐标
            int j = n - 1 - i;
            //当前圈的边长
            int length = n - 2 * i;
            //当前圈的字符
            char currentChar;
            if ((n / 2 - i) % 2 == 0) {
                //距离为偶数
                currentChar = centerChar;
            } else {
                //距离为奇数
                currentChar = outsideChar;
            }

            /*
             * 为当前圈赋值
             */
            for (int k = 0; k < length; ++k) {
                //上边
                matrix[i][i + k] = currentChar;
                //下边
                matrix[i + k][i] = currentChar;
                //左边
                matrix[j - k][j] = currentChar;
                //右边
                matrix[j][j - k] = currentChar;
            }
        }

        /*
         * 除去四个角
         */
        if (n != 1) {
            matrix[0][0] = ' ';
            matrix[0][n - 1] = ' ';
            matrix[n - 1][0] = ' ';
            matrix[n - 1][n - 1] = ' ';
        }

        /*
         * 逐行打印二维数组
         */
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                cout << matrix[i][j];
            }
            cout << endl;
        }
    }
    return 0;
}

3、今年的第几天?–清华大学

描述

输入年、月、日,计算该天是本年的第几天。

输入描述:

包括三个整数年(1<=Y<=3000)、月(1<=M<=12)、日(1<=D<=31)。

输出描述:

输入可能有多组测试数据,对于每一组测试数据, 输出一个整数,代表Input中的年、月、日对应本年的第几天。

示例1

输入:

1990 9 20
2000 5 1

输出:

263
122

题解:

此题较基础,只需把每个月对应的天数加起来即可。但是,日期类问题有一个注意点就是“闰年”,每逢闰年,2月就会有29天。

#include <iostream>
#include <cstdio>

using namespace std;

/*
 * 0~12月份对应的天数
 */
int dayTable[2][13] = {
        {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},    //平年
        {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}     //闰年
};

/**
 * 判断是否为闰年
 * @param year
 * @return
 */
int isLeapYear(int year) {
    //return (year & 3 == 0 && year % 100 != 0) || year % 400 == 0;
    return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}

/**
 * 今年的第几天?--清华大学
 * https://www.nowcoder.com/practice/ae7e58fe24b14d1386e13e7d70eaf04d?tpId=40
 * @return
 */
int main() {
    int year;
    int month;
    int day;
    while (cin >> year >> month >> day) {
        //记录天数
        int dayNumber = 0;
        int row = isLeapYear(year);
        for (int i = 0; i < month; ++i) {
            dayNumber += dayTable[row][i];
        }
        dayNumber += day;
        cout << dayNumber << endl;
    }

    return 0;
}

4 打印日期–华中科技大学

描述

给出年份m和一年中的第n天,算出第n天是几月几号。

输入描述:

输入包括两个整数y(1<=y<=3000),n(1<=n<=366)。

输出描述:

可能有多组测试数据,对于每组数据, 按 yyyy-mm-dd的格式将输入中对应的日期打印出来。

示例1

输入:

2000 3
2000 31
2000 40
2000 60
2000 61
2001 60

输出:

2000-01-03
2000-01-31
2000-02-09
2000-02-29
2000-03-01
2001-03-01

题解:

注意判断“闰年”,按“yyyy-mm-dd”格式输出日期,格式不对也会判错。

#include <iostream>
#include <cstdio>

using namespace std;

/*
 * 空间换时间
 * 二维数组保存平年和闰年0~12月份对应的天数
 */
int dayTable[2][13] = {
        {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},    //平年
        {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}     //闰年
};

/**
 * 判断是否为闰年
 * 若是闰年,则返回1,对应dayTable[1][];反之,返回0,对应dayTable[0][]
 * @param year
 * @return
 */
int isLeapYear(int year) {
    //return (year & 3 == 0 && year % 100 != 0) || year % 400 == 0;
    return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}

/**
 * 打印日期--华中科技大学
 * @return
 */
int main() {
    int year;
    int dayNumber;
    while (cin >> year >> dayNumber) {
        int month = 0;
        int day = 0;
        int row = isLeapYear(year);
        
        /*
         * 计算月份
         * 若dayNumber大于月份的天数,则减去对应天数
         * 同时,month++
         */
        while (dayNumber > dayTable[row][month]) {
            dayNumber -= dayTable[row][month];
            month++;
        }
        day = dayNumber;

        /*
         * 按格式输出日期
         * %2d表示输出宽度为2的整数,超过2位则按实际数据输出,不足2位则右对齐输出
         * %02d表示输出宽度为2的整数,超过2位则按实际数据输出,不足2位则前置补0
         * %5.2f表示输出宽度为5的浮点数,其中小数点后2位,不足5位则右对齐输出
         */
        printf("%04d-%02d-%02d\n", year, month, day);
    }
    return 0;
}

5 手机键盘–清华大学

描述

按照手机键盘输入字母的方式,计算所花费的时间 如:a,b,c都在“1”键上,输入a只需要按一次,输入c需要连续按三次。 如果连续两个字符不在同一个按键上,则可直接按,如:ad需要按两下,kz需要按6下 如果连续两字符在同一个按键上,则两个按键之间需要等一段时间,如ac,在按了a之后,需要等一会儿才能按c。 现在假设每按一次需要花费一个时间段,等待时间需要花费两个时间段。 现在给出一串字符,需要计算出它所需要花费的时间。

输入描述:

一个长度不大于100的字符串,其中只有手机按键上有的小写字母

输出描述:

输入可能包括多组数据,对于每组数据,输出按出Input所给字符串所需要的时间

示例1

输入:

bob
www

输出:

7
7

题解:

手机按键如下:

img

因为有些按键上面有三个字母,有些有四个字母,显然很难找到规律。所以,我们采用预处理策略,采取空间换时间的方式,将每个字母需要的按键次数先记录起来。每当遇到一个字母,直接访问数组便可得到该字母的按键次数。

由此,可得
abc   def   ghi   jkl   mno   pkrs   yuv   wxyz
123   123   123   123   123   1234   123   1234

定义一维数组,记录按键次数
int keyTable[26] = {1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,1,2,3,1,2,3,4};

还有另外一个问题,若两个连续的字符来自同一个按键,按完第一个后中间需要等到一个时间段才能按第二个,那要怎么知道两个字符是否来自同一按键呢?

观察可知,若两个字符来自同一个按键,则字符之间的差值等于两个字符按键次数的差值。

对于与a和c,则有
字符的差值:c-a = 67-65 = 2
字符按键次数的差值:3-1 = 2

对于s和p,则有
字符的差值:s-p = 99-96 = 3
字符按键次数的差值:4-1 = 3
#include <iostream>
#include <cstdio>

using namespace std;

/*
 * 字符对应的按键次数
 */
int keyTable[26] = {1, 2, 3, 1, 2, 3, 1, 2, 3,
                    1, 2, 3, 1, 2, 3, 1, 2, 3,
                    4, 1, 2, 3, 1, 2, 3, 4};

/**
 * 手机按键--清华大学
 * @return
 */
int main() {
    string str;
    while (cin >> str) {
        int time = 0;
        for (int i = 0; i < str.size(); ++i) {
            time += keyTable[str[i] - 'a'];
            //连续的字符来自同一个按键
            if (i != 0 && (str[i] - str[i - 1] ==
                           keyTable[str[i] - 'a'] - keyTable[str[i - 1] - 'a'])) {
                time += 2;
            }
        }
        cout << time << endl;
    }
    
    return 0;
}

三、总结

本章学习收获颇丰,很多的题目都是来自于各大名校的复试题,记录一下笔记,方便自己回顾。

参考教材–《王道计算机考研——机试指南》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

窝在角落里学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值