机试编程(一)

机试编程(一)

目录:

  1. IP地址【华中科大】
  2. 球的半径和体积【清华】
  3. 对称平方数【北理】
  4. 最大公约数【哈工大】
  5. 字符串匹配【上海交大】
  6. 任务调度【中科大】
  7. 比较奇偶数个数【北航】
  8. 密码翻译【北大】
  9. 简单计算器【浙大】
  10. 搬水果【吉大】

1、题目描述:输入一个IP地址串,判断是否合法。【华中科技大学】

  • 输入格式:每行有一个IP地址,IP地址的形式为a.b.c.d,其中a、b、c、d都是整数。
  • 输出格式:可能有多组测试数据,对于每组数据,如果IP地址合法则输出"Yes!”,否则输出"No!”。 合法的IP地址为: a、b、c、d都是0-255的整数。
  • 样例输入:
    • 2
    • 255.255.255.255
    • 512.12.2.3
  • 样例输出:
    • Yes!
    • No!

示例代码:

#include 
#include 
#include 
int main(){
    int count, i;
    while(scanf("%d", &count) != EOF){
        for(i = 0; i < count; i++){
            bool flag = true;
            char *p;
            char ipAddress[100];
            scanf("%s", ipAddress);
            p = strtok(ipAddress, ".");
            while(p){
                int tmp = atoi(p);
                if(tmp < 0 || tmp > 255){
                    flag = false;
                    break;
                }
                p = strtok(NULL, ".");
            }
            if(flag){
                printf("Yes!\n");
            }else{
                printf("No!\n");
            }
        }

    }
    return 0;
}

附注:

(1)stdlib库常用函数:

  • int atoi(const char *str):将str所指向字符串转换为整型。
  • double atof(const char *str):将str所指向字符串转换为浮点型。
  • char* itoa(int value,char*string,int radix):整型转换为字符串,radix:转换进制数。

(2)string库常用函数:

  • void *memset(void *str, int c, size_t n):复制一个无符号字符c到参数str所指向的字符串的前 n 个字符。常用数组置零:memset(array, 0, sizeof(array))。
  • char *strtok(char *str, const char *delim):分解字符串str为一组字符串,delim为分隔符。
  • char *strstr(const char *str, const char *str2):在字符串 str1中查找第一次出现字符串 str2的位置,不包含终止符 '\0',若str2是str1的子串,则返回str2在str1的首次出现的地址;如果str2不是str1的子串,则返回NULL。
  • size_t strlen(const char *str):计算字符串str的长度,直到空结束字符,但不包括空结束字符。
  • char *strcpy(char *str1, const char *str2):把str2所指向的字符串复制到str1。
  • char *strncpy(char *str1, const char *str2, int n):把str2所指向的字符串复制到str1,最多复制 n 个字符。
  • char *strcpy(char *str1, const char *str2) :把str2所指向的字符串复制到str1。

2、题目描述:输入球的中心点和球上某一点的坐标,计算球的半径和体积。【清华大学】

  • 输入格式:球的中心点和球上某一点的坐标,以如下形式输入:x0 y0 z0 x1 y1 z1
  • 输出格式:输入可能有多组,对于每组输入,输出球的半径和体积,并且结果保留三位小数。为避免精度问题,PI值请使用arccos(-1)。
  • 样例输入:
    • 0 0 0 1 1 1 
  • 样例输出:
    • 1.732 21.766

示例代码:

#include 
#include 
int main(){
    double pi = acos(-1), radius, volume;
    double x0, y0, z0, x1, y1, z1;
    while(scanf("%lf%lf%lf%lf%lf%lf", &x0, &y0, &z0, &x1, &y1, &z1) != EOF){
        radius = sqrt(pow((x0 - x1), 2) + pow((y0 - y1), 2) + pow((z0 - z1), 2));
        volume = 4.0 / 3 * pi * pow(radius, 3);
        printf("%.3lf %.3lf", radius, volume);
    }
    return 0;
}

附注:

(1)math库常用函数:

  • double acos(double x):返回以弧度表示的 x 的反余弦,弧度区间为 [0, pi]。
  • double cos(double x):返回 x 的余弦。
  • double pow(double x, double y):返回 x 的 y 次幂。
  • double sqrt(double x):返回x的平方根。
  • double ceil(double x):返回大于或等于 x 的最小的整数值。
  • double floor(double x):返回小于或等于 x 的最大的整数值。
  • double fabs(double x):返回 x 的绝对值。

3、题目描述:打印所有不超过n(n<256)的,其平方具有对称性质的数。如11*11=121。【北京理工大学】

  • 输入格式:无
  • 输出格式:每行一个数,表示对称平方数。
  • 样例输入:无
  • 样例输出:无

示例代码:

#include 
//求反序数
int reverse(int num){
    int revNum = 0;
    while(num != 0){
        revNum *= 10;
        revNum += num % 10;
        num /= 10;
    }
    return revNum;
}
int main(){
    for(int i =1; i < 256; i++){
        int num = i * i;
        if(reverse(num) == num){
            printf("%d\n", i);
        }
    }
    return 0;
}

4、题目描述:输入两个正整数,求其最大公约数。【哈尔滨工业大学】

  • 输入格式:测试数据有多组,每组输入两个正整数。
  • 输出格式:对于每组输入,请输出其最大公约数。
  • 样例输入:
    • 49 14
  • 样例输出:
    • 7

示例代码1:

#include 
int main(){
    int a, b, minValue, result = 1;
    scanf("%d%d", &a, &b);
    minValue = a < b ? a : b;
    if(a % b == 0){
        printf("%d\n", b);
    }else if(b % a == 0){
        printf("%d\n", a);
    }else{
        for(int i = 2; i <= minValue / 2; i++){
            if(a % i == 0 && b % i == 0){
                a /= i;
                b /= i;
                result *= i;
            }
        }
    }
    printf("%d\n", result);
    return 0;
}

示例代码2:

#include 
int main(){
    int a, b, tmp;
    while(scanf("%d%d", &a, &b) != EOF){
        while(b){
            tmp = a % b;
            a = b;
            b = tmp;
        }
        printf("%d\n", a);
    }
    return 0;
}

5、题目描述:Finding all occurrences of a pattern in a text is a problem that arises frequently in text-editing programs.
Typically,the text is a document being edited,and the pattern searched for is a particular word supplied by the user.
We assume that the text is an array T[1..n] of length n and that the pattern is an array P[1..m] of length m<=n.We further assume that the elements of P and  T are all alphabets(∑={a,b...,z}).The character arrays P and T are often called strings of characters.
We say that pattern P occurs with shift s in the text T if 0<=s<=n and T[s+1..s+m] = P[1..m](that is if T[s+j]=P[j],for 1<=j<=m).
If P occurs with shift s in T,then we call s a valid shift;otherwise,we calls a invalid shift.
Your task is to calculate the number of vald shifts for the given text T and p attern P.【上海交通大学】

  • 输入格式:For each case, there are two strings T and P on a line,separated by a single space.You may assume both the length of T and P will not exceed 10^6.
  • 输出格式:You should output a number on a separate line,which indicates the number of valid shifts for the given text T and pattern P.
  • 样例输入:
    • abababab abab
  • 样例输出:
    • 3

示例代码:

#define MAX_SIZE 1000010
#include 
#include 
int main(){
    char str[MAX_SIZE], subStr[MAX_SIZE];
    char *pStr = str;
    int appearCount;
    while(scanf("%s%s", str, subStr) != EOF){
        appearCount = 0;
        char *tmp = strstr(pStr, subStr);
        while(tmp){
            pStr = tmp + 1;
            appearCount++;
            tmp = strstr(pStr, subStr);
        }
        printf("%d\n", appearCount);
    }
    return 0;
}

6、题目描述:读入任务调度序列,输出n个任务适合的一种调度方式。【中国科技大学】

  • 输入格式:输入包含多组测试数据。
    每组第一行输入一个整数n(n<100000),表示有n个任务。
    接下来n行,每行第一个表示前序任务,括号中的任务为若干个后序任务,表示只有在前序任务完成的情况下,后序任务才能开始。若后序为NULL则表示无后继任务。
  • 输出格式:输出调度方式,输出如果有多种适合的调度方式,请输出字典序最小的一种。
  • 样例输入:
    • 4
    • Task0(Task1,Task2)
    • Task1(Task3)
    • Task2(NULL)
    • Task3(NULL)
  • 样例输出:
    • Task0 Task1 Task2 Task3

示例代码:

#include 
#include 
#include 
#define MAXSIZE 5000

//运用邻接表的思想
typedef struct ArcNode{        //边表
    int adjvex;                //该边所指向的结点位置
    struct ArcNode *nextArc;   //指向下一条边的指针
}ArcNode;

typedef struct TaskNode{       //任务结点表
    char name[10];             //任务名称
    int indegree;              //记录入度
    struct ArcNode *firstArc;  //指向任务第一条边的指针
}TaskNode;

typedef struct StackNode{      //定义栈结点
    char name[10];             //任务名称
    struct StackNode *next;    //指向下一个任务
    struct ArcNode *firstArc;  //指向任务第一条边的指针
}StackNode;

typedef struct MyStack{        //定义栈
    struct StackNode *top;     //栈顶指针
    int taskCount;             //栈中任务数量
}MyStack;

//初始化栈
MyStack* InitStack(){
    MyStack *S = (MyStack *)malloc(sizeof(MyStack));
    if(!S){
        printf("MyStack Init failed.\n");
        exit(1);
    }
    S->top = NULL;
    S->taskCount = 0;
    return S;
}

//入栈
void Push(MyStack *S, TaskNode *taskNode){
    StackNode * stackNode = (StackNode *)malloc(sizeof(StackNode));
    if(!stackNode){
        printf("StackNode memory allocation failed.\n");
        exit(1);
    }
    strcpy(stackNode->name, taskNode->name);
    stackNode->next = S->top;
    stackNode->firstArc = taskNode->firstArc;
    S->top = stackNode;
    S->taskCount++;
}

//出栈
void Pop(MyStack *S, StackNode **stackNode){
    *stackNode = S->top;
    S->top = (*stackNode)->next;
}

//拓扑排序思想输出任务调度序列
void TopoSort(TaskNode *taskList, int N, MyStack *S){
    int popCount = 0;
    for(int i = N - 1; i >= 0; i--){
        if((taskList + i)->indegree == 0){   //入度为零,入栈
            Push(S, (taskList + i));
			(taskList + i)->indegree = -1;
        }
    }
    while(S->top){
        StackNode *stackNode = NULL;
        Pop(S, &stackNode);
        popCount++;
        printf("%s ", stackNode->name);
        ArcNode *arc = stackNode->firstArc;
        while(arc){
			--((taskList + arc->adjvex)->indegree);
            arc = arc->nextArc;
        }
		if(!S->top){
			for(int i = N - 1; i >= 0; i--){
				if((taskList + i)->indegree == 0){   //入度为零,入栈
					Push(S, (taskList + i));
					(taskList + i)->indegree = -1;
				}
			}
		}
        free(stackNode);
        stackNode = NULL;
    }
    if(popCount < N){ //弹出的任务数少于N,则任务存在死锁
        printf("Task deadlock.\n");
    }else{
        printf("\n");
    }
}

//删除字符串中某个特定字符(删除右括号)
char* DelChar(char *str, char ch){
    int j = 0;
    for(int i = 0; str[i] != '\0'; i++){
        if(str[i] != ch){
            str[j++] = str[i];
        }
    }
    for(; str[j] != '\0'; j++){
        str[j] = '\0';
    }
    return str;
}

//初始化任务列表
TaskNode* InitTaskList(int N){
    TaskNode *taskListPoint = (TaskNode *)malloc(sizeof(TaskNode) * N);  //为任务数组分配内存
    if(!taskListPoint){           //内存分配失败
        printf("TaskNode memory allocation failed.\n");
        exit(1);
    }
    for(int i = 0; i < N; i++){      //初始化任务数组
        char taskName[10];
        char secondName[6];
        strcpy(taskName, "Task");
        itoa(i, secondName, 10);
        strcat(taskName, secondName);
        strcpy((taskListPoint + i)->name, taskName);
        (taskListPoint + i)->firstArc = NULL;
        (taskListPoint + i)->indegree = 0;
    }
    return taskListPoint;
}

//构造任务前后置关系
void InitTaskRelation(int N, TaskNode *taskListPoint){
    for(int i = 0; i < N; i++){
        TaskNode *pTask = taskListPoint;
        char inputStr[MAXSIZE];              //用户输入的任务调度序列
        scanf("%s", inputStr);
        char *pBracket = strchr(inputStr, '(');
        char code[6];                        //任务编号变量
        strncpy(code, inputStr + 4, strlen(inputStr) - strlen(pBracket)); //取出左括号前的前置任务编号
        int taskNodeCode = atoi(code);       //将前置任务编号从字符型转换为整型
        pTask = pTask + taskNodeCode;        //指向一个具体前置任务
        if(!strstr(inputStr, "NULL")) {
            DelChar(pBracket + 1, ')');      //删除右括号
            char *pNext = strtok(pBracket + 1, ","); //按照逗号分割任务序列
            for(int j = 0; pNext; j++){      //头插法插入后置任务
				TaskNode *taskHead = taskListPoint;
                struct ArcNode *arcNode = (struct ArcNode*)malloc(sizeof(struct ArcNode));  //创建一个边结点
                char taskCode[6];            //任务编号变量
                strcpy(taskCode, pNext + 4); //取出任务编号
                arcNode->adjvex = atoi(taskCode);  //将任务编号赋值给边结点所指任务位置变量
                arcNode->nextArc = pTask->firstArc;
                pTask->firstArc = arcNode;
                (taskHead + atoi(taskCode))->indegree++;
                pNext = strtok(NULL, ",");
            }
        }
    }
}

//打印函数,用于测试输出
void print(int N, TaskNode *taskListPoint){
    for(int i = 0; i < N; i++){
        printf("name=%s\n", (taskListPoint + i)->name);
        printf("indegree:%d\n", (taskListPoint + i)->indegree);
        struct ArcNode* arcNode = (taskListPoint + i)->firstArc;
        while(arcNode){
            printf("它的后置任务是:%d\n", arcNode->adjvex);
            arcNode = arcNode->nextArc;
        }
    }
}

int main(){
    int N;  //N:有n个任务
    while(scanf("%d", &N) != EOF){
        MyStack *S = InitStack();
        TaskNode *taskListPoint = InitTaskList(N);
        InitTaskRelation(N, taskListPoint);
		//print(N, taskListPoint);
        TopoSort(taskListPoint, N, S);
        free(taskListPoint);    //释放内存空间
        taskListPoint = NULL;
    }
    return 0;
}

附注:

(1)字符串复制时,不能直接赋值,要用strcpy。

(2)当要往指针所指向变量赋值时,应先分配内存空间,分配时要检验是否成功,成功就可以使用指针。指针使用完成,要对申请的内存空间进行释放。malloc和free要成对使用。

(3)指针定义时,若没有指向,需要初始化为空,避免称为野指针,造成内存泄露。

(4).和->的区别:a).前面是结构体;b)->前面是指向结构体的指针变量;c)(*ArcNode).adjvex等效于ArcNode->adjvex。

7、题目描述:第一行输入一个数,为n,第二行输入n个数,这n个数中,如果偶数比奇数多,输出NO,否则输出YES。【北京航天航空大学】

  • 输入格式:输入有多组数据。每组输入n,然后输入n个整数(1<=n<=1000)。
  • 输出格式:如果偶数比奇数多,输出NO,否则输出YES。
  • 样例输入:
    • 5
    • 1 5 2 4 3
  • 样例输出:
    • YES

示例代码:

#include 
int main(){
	int N;
	while(scanf("%d", &N) != EOF){
		int inputNumber, evenCount = 0, oddCount = 0;
		for(int i = 0; i < N; i++){
			scanf("%d", &inputNumber);
			if(inputNumber % 2 == 0){
				evenCount++;
			}else{
				oddCount++;
			}
		}
		evenCount > oddCount ? printf("NO\n") : printf("YES\n");
	}
	return 0;
}

8、题目描述:在情报传递过程中,为了防止情报被截获,往往需要对情报用一定的方式加密,简单的加密算法虽然不足以完全避免情报被破译,但仍然能防止情报被轻易的识别。我们给出一种最简的的加密方法,对给定的一个字符串,把其中从a-y,A-Y的字母用其后继字母替代,把z和Z用a和A替代,则可得到一个简单的加密字符串。【北京大学】

  • 输入格式:读取这一行字符串,每个字符串长度小于80个字符。
  • 输出格式:对于每组数据,输出每行字符串的加密字符串。
  • 样例输入:
    • 1
    • Hello! How are you!
  • 样例输出:
    • Ifmmp! Ipx bsf zpv!

示例代码:

#include 
#include 
void deal(char str[]){
	int i = 0;
	while(str[i] != '\0'){
		if(str[i] == 'Z'){
			str[i] = 'A';
		}else if(str[i] == 'z'){
			str[i] = 'a';
		}else if((str[i] >= 'a' && str[i] <= 'y') || (str[i] >= 'A' && str[i] <= 'Y')){
			str[i] += 1;
		}
		i++;
	}
}

int main(){
	char inputStr[90];
	while(gets(inputStr)){
		deal(inputStr);
		printf("%s ",inputStr);
	}
	return 0;
}

附注:

(1)输入带空格的一行:scanf("%[^\n]",str)。

9、题目描述: 读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。【浙江大学】

  • 输入格式:测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。
  • 输出格式:对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
  • 样例输入:
    • 1 + 2
    • 4 + 2 * 5 - 7 / 11
    • 0
  • 样例输出:
    • 3.00
    • 13.36

示例代码:

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

stack oper;      //临时操作数栈
stack result;  //后缀表达式结果栈
 
//删除空白字符
void deleteSpace(string &str){
	str.erase(remove(str.begin(), str.end(), ' '), str.end());
}
 
//取得数字
double GetNumber(string s, int &index){ 
	double number = 0;
	while(isdigit(s[index])){
		number = number * 10 + s[index] - '0';
		index++;
	}
	return number;
}
 
//设置操作符优先级
int Priority(char c){
	if(c == '*' || c== '/'){ //乘除优先级为2,加减优先级为1
		return 2;
	}else{
		return 1;
	}
}
 
double Calc(double a, double b, char c){
	if(c == '+'){
		return a + b;
	}else if(c == '-'){
		return a - b;
	}else if(c == '*'){
		return a * b;
	}else{
		return a / b;
	}
}
 
//对加减乘除进行处理
double Deal(string s){
	int i = 0;
	do{
		if(isdigit(s[i])){
			result.push(GetNumber(s, i));  //取得运算数
		}
		//其后还有运算符 && 临时操作数栈为空||栈顶运算符优先级小于待入栈运算符
		if(i < s.length() && (oper.empty() || Priority(oper.top()) < Priority(s[i]))){ 
			oper.push(s[i++]);    //操作符入临时操作数栈
		}
		//其后没有运算符  || 栈顶运算符优先级大于等于待入栈运算符
		else if(i == s.length() || Priority(oper.top()) >= Priority(s[i])){  
			double b = result.top();
			result.pop();
			double a = result.top();
			result.pop();
			result.push(Calc(a, b, oper.top()));
			oper.pop();	
		}
	}while(i < s.length() || !oper.empty());
	return result.top();
}
 
int main(){
	string inputStr;
	while(getline(cin, inputStr)){
		if(inputStr == "0"){
			break;
		}
		deleteSpace(inputStr);
		cout.setf(ios::fixed);
		cout << fixed << setprecision(2) << Deal(inputStr) << endl;
		stack().swap(result);  //重置栈
		stack().swap(oper);
	}
	return 0;
}

附注:

(1)中缀表达式转换为后缀表达式思路:

  1. 一个数组oper(栈)存放临时操作数,一个数组result(栈)存放后缀表达式;
  2. *和/优先级高于+和-优先级;
  3. 若为操作数,直接入栈到数组result中;
  4. 若为运算符:
    1. 若数组oper为空栈,直接入栈;
    2. 若数组oper为非空栈(有运算符):
      • 若栈顶运算符优先级小于待入栈运算符,待入栈运算符入栈到oper数组;
      • 若栈顶运算符优先级大于或等于待入栈运算符,栈顶元素出栈到result数组,重复步骤4;
  5. 中缀表达式扫描完毕,将oper数组中操作数入栈到result数组。

10、题目描述:在一个果园里,小明已经将所有的水果打了下来,并按水果的不同种类分成了若干堆,小明决定把所有的水果合成一堆。每一次合并,小明可以把两堆水果合并到一起,消耗的体力等于两堆水果的重量之和。当然经过n‐1次合并之后,就变成一堆了。小明在合并水果时总共消耗的体力等于每次合并所耗体力之和。假定每个水果重量都为1,并且已知水果的种类数和每种水果的数目,你的任务是设计出合并的次序方案,使小明耗费的体力最少,并输出这个最小的体力耗费值。例如有3种水果,数目依次为1,2,9。可以先将1,2堆合并,新堆数目为3,耗费体力为3。然后将新堆与原先的第三堆合并得到新的堆,耗费体力为 12。所以小明总共耗费体力=3+12=15,可以证明 15 为最小的体力耗费值。【吉林大学】

  • 输入格式:每组数据输入包括两行,第一行是一个整数 n(1<=n<=10000),表示水果的种类数。第二行包含 n 个整数,用空格分隔,第i个整数(1<=ai<=1000)是第 i 种水果的数目。
  • 输出格式:对于每组输入,输出一个整数并换行,这个值也就是最小的体力耗费值。输入数据保证这个值小于 2^31。
  • 样例输入:
    • 3
    • 9 1 2
    • 0
  • 样例输出:
    • 15

示例代码:

#include 
#include 

int cmp(const void *a, const void *b){
	return *(int *)b - *(int *)a;
}

void AdjustSort(int fruit[], int n){
	int i, tmp, newNumber = fruit[n - 1];
	for(i = n - 2; i >= 0; i--){
		if(newNumber > fruit[i]){
			fruit[i + 1] = fruit[i];
		}else{
			break;
		}
	}
	fruit[i + 1] = newNumber;
}

int main(){
	int n;
	while(scanf("%d", &n) != EOF){
		int *fruit = (int *)malloc(sizeof(int) * n);
		for(int i = 0; i < n; i++){
			scanf("%d", &fruit[i]);
		}
		qsort(fruit, n, sizeof(int), cmp);//由小到大排序
		int result = 0;
		while(n > 1){
			int min = fruit[--n];
			int secondMin = fruit[--n];
			fruit[n++] = min + secondMin;
			result += min + secondMin;
			AdjustSort(fruit, n);
		}
		printf("%d\n", result);
	}
	return 0;
}

附注:

(1)qsort函数:对数组元素进行排序,void qsort(fruit, n, sizeof(int), cmp)。

  • 由大到小排序:
    • int cmp(const void *a, const void *b){
    • return *(int *)b - *(int *)a;
    • }
  • 由小到大排序:
    • int cmp(const void *a, const void *b){
    • return *(int *)a - *(int *)b;
    • }

参考文献:

[1]杨泽邦、赵霖. 计算机考研——机试指南(第2版). [M]北京:电子工业出版社,2019.11;
 

你可能感兴趣的:(机试编程)