题目91:乒乓球
问题描述
国际乒联主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。其中11分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。明明就是其中一位,他退役之后走上了乒乓球研究工作,意图弄明白11分制和21分制对选手的不同影响。在开展他的研究之前,明明首先需要对他多年比赛的统计数据进行一些分析,所以需要你的帮忙。 (注:11(21)分制,在一局比赛中,选手A先得到11(21)分且此时领先选手B 2分或2分以上时,则选手A赢得此局;若当双方打成10(20)平后,则先多得2分的一方为胜方,赢得此局。)
明明通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在11分制和21分制下,双方的比赛结果(截至记录末尾)。一局比赛的开始比分为0比0。 比如现在有这么一份记录,(其中W表示明明获得一分,L表示明明的对手获得一分):
WWWWWWWWWWWWWWWWWWWWWWLW
在11分制下,此时比赛的结果是明明第一局11比0获胜,第二局11比0获胜,正在进行第三局,当前比分1比1。
在21分制下,此时比赛结果是明明第一局21比0获胜,正在进行第二局,当前比分2比1。
再如有这么一份记录,(其中W表示明明获得一分,L表示明明的对手获得一分):
WLWLWLWLWLWLWLWLWLWLWLWLWL
在11分制下,此时比赛的结果是明明和对手打成13比13,这局比赛仍没有分出胜负,因为任何一方都没有领先其对手2分。
在21分制下,此时比赛的结果是明明和对手打成13比13,这局比赛仍在进行中。
由于明明参加过多年的比赛,比赛的数据量相当庞大,如果仅仅使用手工统计,在短时间内统计出结果对于明明来说是相当困难的。因此明明求助于你,希望你能写一个程序,帮助他快速地统计出结果来。
明明的问题可以归结为:给你一系列的比赛数据(WL形式),分别按照11分制和21分制的比赛规则进行统计,然后输出统计结果。
输入说明
你写的程序要求从标准输入设备中读入测试数据作为你所写程序的输入数据。标准输入设备中有多组测试数据,每行包括一串有W、L和E组成比赛结果,其中W表示明明得一分,L表示明明的对手得一分,E表示该组测试数据的结束,也就是说E后面的W、L应该忽略,无需处理。每行的长度不会超过30个字符。每组测试数据与其后一组测试数据之间没有任何空行,第一组测试数据前面以及最后一组测试数据后面也都没有任何空行。
输出说明
对于每一组测试数据,你写的程序要求计算出一组相应的运算结果,并将每组运算结果作为你所写程序的输出数据依次写入到标准输出设备中。
每组运算结果由两部分组成,其中第一部分是11分制下的结果,第二部分是21分制下的结果,两部分之间由一个空行分隔。
每部分由若干行组成,每一行对应一局比赛的比分(按比赛信息输入顺序),每局的比分按如下形式表示:m:n,其中m表示明明的得分,n表示明明的对手的得分,m、n之间用一个冒号隔开。
输出时,每组运算结果与其后一组运算结果之间有一个空行,第一组运算结果前面以及最后一组运算结果后面没有任何空行或其他任何字符。 注:通常,显示屏为标准输出设备。
总结:
-
计分函数 process_and_print()按指定赛制(11分或21分)统计并输出比分,record:比赛记录字符串(由W和L组成),target_score:目标分数(11或21)。对两种获胜条件进行判断,任何一方达到目标分数(11或21)并领先至少2分或平局后净胜2分,first_game 确保即使整组没有得分也输出0:0
-
逐字符处理 W(得分)和 L(失分),每得一分后判断是否满足获胜条件,当一局结束时,输出当前比分并重置为0:0,循环结束后,如果还有未完成的比分(或整组没有比分),输出最后比分
-
对于每一组输入数据,读取字符判断类型,若读取 'E',结束当前组,开始处理(process_and_print() 函数);若读取'W'/'L',存入数组 record[] 中;若读取EOF,表明文件结束,处理最后一组测试数据;若读取换行符,忽略
-
first 用于控制空行的输出,在除第一组数据外的每组数据输出前输出一个空行
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//处理一种赛制并输出结果
void process_and_print(const char *record, int target_score){
int w = 0, l = 0; //当前局比分
int first_game = 1; //是否是该组的第一个输出
for(int i = 0; record[i] != '\0'; i++) {
if(record[i] == 'E')
break;
if(record[i] == 'W')
w++;
else if(record[i] == 'L')
l++;
//检查是否结束一局
int game_end = 0;
//达到目标分数且领先至少2分
if((w >= target_score || l >= target_score) && abs(w - l) >= 2){
game_end = 1;
}
//平分后(target_score-1平)领先2分
if(w >= target_score-1 && l >= target_score-1 && abs(w - l) == 2){
game_end = 1;
}
if(game_end){
printf("%d:%d\n", w, l);
w = l = 0;
first_game = 0;
}
}
//输出未完成的局(如果有比分或一局都没开始)
if(w > 0 || l > 0 || first_game){
printf("%d:%d\n", w, l);
}
}
int main() {
char record[1000]; //存储一组的记录
int group_count = 0;
int first = 1; //是否是第一组
while(1) {
int idx = 0;
int found_E = 0;
//读取一组数据(可能跨越多行)
while(!found_E){
//检查是否到达文件末尾
int ch = getchar();
if(ch == EOF){
//文件结束,处理最后的数据
if(idx > 0){
record[idx] = '\0';
//输出结果
if(!first){
printf("\n");
}
process_and_print(record, 11);
printf("\n");
process_and_print(record, 21);
}
return 0;
}
if(ch == 'E'){
record[idx++] = 'E';
found_E = 1;
}
else if(ch == 'W' || ch == 'L'){
record[idx++] = ch;
}
//忽略其他字符(包括换行符)
}
record[idx] = '\0'; //确保字符串结束
//输出组间分隔(除了第一组)
if(!first){
printf("\n");
}
first = 0;
//处理并输出该组结果
process_and_print(record, 11);
printf("\n");
process_and_print(record, 21);
}
return 0;
}
题目92:字符串统计
问题描述
明明最近在做一个有关字符串的统计工作。两个由小写字母组成的字符串s1和s2,明明需要统计出以下四种关系:
(1)在s1或s2中存在的字母(包括在s1和s2中都存在的字母);
(2)在s1中且在s2中的字母;
(3)在s1中但不在s2中的字母,在s2中但不在s1中的字母;
(4)不在s1中且也不在s2中的字母;
例如两个字符串s1为"lkjsvoahs",s2为"qglhskjdfg":
(1)在s1或者在s2或者s1、s2中都存在的字母:adfghjkloqsv;
(2)在s1中且在s2中的字母:hjkls;
(3)在s1中但不在s2中的字母,在s2中但不在s1中的字母:adfgoqv;
(4)不在s1中且也不在s2中的字母:bceimnprtuwxyz;
明明统计了很久,但是由于统计过程十分繁琐,且很容易出错,导致明明的进度非常慢,很有可能因为统计不完而错过了晚上的约会。因此明明想请你帮个忙,帮他写一个程序,用程序来统计出以上几项内容。
明明的问题可以归结为:
输入两串由小写字母组成的字符串s1和s2,比较其中的字母,输出以下四项,输出的字母以字典顺序排列:
(1)在s1或s2中存在的字母(包括在s1和s2中都存在的字母);
(2)在s1中且在s2中的字母;
(3)在s1中但不在s2中的字母,在s2中但不在s1中的字母;
(4)不在s1中且也不在s2中的字母;
例如字符串s1为sadf,s2为asdf,则需输出以下四行(注意输出的格式):
in s1 or s2:adfs
in s1 and s2:adfs
in s1 but not in s2 ,or in s2 but not in s1:
not in s1 and s2:bceghijklmnopqrtuvwxyz
输入说明
你写的程序要求从标准输入设备中读入测试数据作为你所写程序的输入数据。标准输入设备中有多组测试数据,每组测试数据两行,每组测试数据的第一行为字符串s1,每组测试数据的第二行为字符串s2;s1和s2都由小写英文字母组成,且长度不超过26个字符。测试数据与其后一组测试数据之间没有任何空行,第一组测试数据前面以及最后一组测试数据后面也都没有任何空行。
输出说明
对于每一组测试数据,你写的程序要求计算出一组相应的运算结果,并将这一组运算结果作为你所写程序的输出数据依次写入到标准输出设备中。
每组运算结果由四行组成:
第一行为在s1或者在s2或者s1、s2中都存在的字母;
第二行为在s1中且在s2中的字母;
第三行为在s1中但不在s2中的字母,在s2中但不在s1中的字母;
第四行为不在s1中且也不在s2中的字母;
具体格式请参考样例输出。
每组运算结果其行首和行尾都没有任何空格,每组运算结果与其后一组运算结果之间有一个空行,最后一组运算结果后面没有空行。
注:通常,显示屏为标准输出设备。
总结:
-
first 标记是否为第一组数据,用于控制空行的输出,除一组数据外的数据在输出前先输出一个空行
-
%s 用于输入字符串,数组 state[26] 对应26个英文字母的位置,遍历字符串 s1,s2 得到数组 state[] ,用于标记字母在字符串中的情况,0表示不存在字符串中,1表示在s1中,2表示在s2中,3表示在s1和s2中。字符串中的字符 - 'a' 即为该字符在26个字母中的位置,如 idx = s1[i] - 'a'
-
根据 state[] 数组进行输出,若字母在s1中且在s2中的,即 status[i] == 1 || status[i] == 2 || status[i] == 3,则按位置输出字母,即 printf("%c", 'a' + i);若字母在s1中且在s2中,即 status[i] == 3,输出 'a' + i;若字母在s1中但不在s2中,或在s2中但不在s1中,即 status[i] == 1 || status[i] == 2,输出 'a' + i;若字母不在s1中且也不在s2中,即 status[i] == 0,输出 'a' + i
cpp
#include <stdio.h>
#include <string.h>
int main() {
char s1[30], s2[30];
int first = 1; //标记是否是第一组测试数据
while(scanf("%s%s", s1, s2) == 2) {
//标记数组,0表示不存在,1表示在s1,2表示在s2,3表示在s1和s2
int status[26] = {0}; //0:不在任何字符串,1:在s1,2:在s2,3:在s1和s2
int len1 = strlen(s1);
int len2 = strlen(s2);
//处理s1
for(int i = 0; i < len1; i++){
int idx = s1[i] - 'a';
if(status[idx] == 0)
status[idx] = 1;
else if(status[idx] == 2)
status[idx] = 3;
}
// 处理s2
for(int i = 0; i < len2; i++){
int idx = s2[i] - 'a';
if(status[idx] == 0)
status[idx] = 2;
else if(status[idx] == 1)
status[idx] = 3;
}
//输出组间空行(除了第一组)
if(!first) {
printf("\n");
}
first = 0;
//在s1或s2中存在的字母
printf("in s1 or s2:");
for(int i = 0; i < 26; i++){
if(status[i] == 1 || status[i] == 2 || status[i] == 3){
printf("%c", 'a' + i);
}
}
printf("\n");
//在s1中且在s2中的字母
printf("in s1 and s2:");
for(int i = 0; i < 26; i++){
if(status[i] == 3){
printf("%c", 'a' + i);
}
}
printf("\n");
//在s1中但不在s2中的字母,在s2中但不在s1中的字母
printf("in s1 but not in s2 ,or in s2 but not in s1:");
for(int i = 0; i < 26; i++){
if(status[i] == 1 || status[i] == 2){
printf("%c", 'a' + i);
}
}
printf("\n");
//不在s1中且也不在s2中的字母
printf("not in s1 and s2:");
for(int i = 0; i < 26; i++){
if(status[i] == 0){
printf("%c", 'a' + i);
}
}
printf("\n");
}
return 0;
}
题目93:隐藏口令
问题描述
有时候程序员有很奇怪的方法来隐藏他们的口令。
Billy"Hacker"Geits会选择一个字符串S(由L个小写字母组成,5<=L<=100,000),然后他把S顺时针绕成一个圈。
如字符串cbadfa,绕成一个圈后,我们认为字符串首尾相连。
每次取其中一个字母作为起始字母,并顺时针依次取字母而组成一个字符串。这样将得到一些字符串。
比如字符串cbadfa,按照以上规则取出的字符串有:
cbadfa badfac adfacb dfacba facbad acbadf
我们找到最小的那个字符串,可知为acbadf,也可知道它的第一个字符'a'在原字符串cbadfa中为第6个字符(位置从1开始),
将得到的结果6减1得到5,这就是我们需要的口令。
再比如字符串alabala,绕成一个圈后,每次取其中一个字母作为起始字母,并顺时针依次取字母而组成一个字符串。这样将得到一些字符串:
alabala labalaa abalaal balaala alaalab laalaba aalabal
我们找到最小的那个字符串,可知为aalabal,它的第一个字母'a'在原字符串中位置为7,7-1=6,则6为口令。
注:如果按照规则有两个字符串都是最小的,则取前面那一个。
输入说明
第一行:一个数L
第二行及之后:字符串S。
注意:字符串S可跨多行,但其中的'\n'不算成S中的字符
输出说明
一行,为得到的口令。
无多余空格或空行。
总结:
-
使用 while 循环存储长度为 L 的字符串,一个字符一个字符地读取,若读取的字符不为换行符,则存入字符数组 S[L + 1] 中
-
使用二维数组 arr[L][L + 1] 存储字符串的循环子串,存储完成后,使用 strcmp() 函数比较字符串的大小,遍历所有循环子串找到最小的子串,输出该子串在二维数组中的下标
cpp
#include <stdio.h>
#include <string.h>
int main() {
int L;
scanf("%d\n", &L);
char S[L + 1];
int count = 0;
char c;
//读取 L 个非换行符字符
while(count < L){
c = getchar();
if(c == EOF) break;
if(c != '\n' && c != '\r'){
S[count++] = c;
}
}
S[L] = '\0';
char arr[L][L + 1];
for(int i = 0; i < L; i++){
int k = 0;
for(int j = i; j < i + L; j++){
arr[i][k++] = S[j % L];
}
arr[i][k] = '\0';
}
int min = 0;
for(int i = 1; i < L; i++) {
if(strcmp(arr[i], arr[min]) < 0) {
min = i; //找到更小的
}
}
printf("%d", min);
return 0;
}


翻译:
2.计算机结构
计算机结构是新计算机系统的设计和分析。计算机结构设计师研究通过增加计算机速度,内存容量和可靠性以及降低计算机成本和电量消耗的方式来改善计算机。计算机结构设计师开发软件和硬件的模型分析现存的和提出的计算机设计的性能,然后用这个分析去指导新计算机的开发。他们经常涉及新计算机的工程,因为他们模型的准确性依赖计算机电路的设计。很多计算机结构分析师对开发专门从事特殊应用程序的计算机有兴趣,例如图像处理,信号处理,或者机器系统的控制。针对特定任务的计算机结构优化经常放弃高性能,低成本,或两者都放弃。
3.人工智能
人工智能(AI)研究寻找使计算机和机器能模仿人类智能和感官处理能力,用计算机塑造人类行为去提高我们智能的理解。AI研究的很多分支包括机器学习,推理,认知,知识表示,问题解决,基于案例的推理,自然语言理解,声音识别,计算机视觉和人工神经网络。
4.机器人技术
计算机科学的另一个已得到广泛实际应用的领域是机器人技术,计算机控制机器设备的设计和开发。机器人复杂性的范围从玩具到自动化的工厂组装线,将人类从繁琐的,重复的或者危险的任务中解放出来。机器人也被雇佣在速度,精度,连贯性或者洁净度远超人类可以完成的地方。机器人专家(参与机器人技术的科学家)研究控制机器人的很多方面。这些方面包括塑造机器人的身体属性,塑造它的环境,计划它的行为,高效引导它的机制,用传感器提供控制系统的反馈,确保它的行为的安全性。他们也研究简化控制程序的创造的方式。研究的一个领域试图给机器人提供更多人类的灵巧性和适应性,并且与AI密切相关。
单词:
