1018.锤子剪刀布
题目分析:
乍看起来还是比较容易,不过实现起来还是有一些麻烦。这一题没有什么坑点需要额外注意,不过需要仔细。
为了相对简便地判断胜负关系,首先判断两字符是否相等,若相等则直接将平局数量加一;否则需要根据情况进行判断。
这里我没有用switch,用switch语句的话对各种情况进行判断难免导致代码冗长。为了方便地判断胜负,编写了一个函数,输入一个字符,返回其能赢的字符,那么只需要比较对应另一个玩家的手势的字符是否与函数返回值相等便能知是赢了还是输了,当然这个函数本身也需要if判断,但比较次数至多是2次。
同时,为了方便排序,在解不唯一时按字母排序,可直接将储存各手势赢的次数的数组元素就设置成按字母序排序,即第一个元素存B胜利次数,第二个存C胜利次数,第三个存J胜利次数,这样直接一次按胜利次数决定是否需要更新输出点即可,不必再考虑字母序。
源代码
#include <stdio.h>
struct result{
int win=0,equal=0,lose=0;
};
char winGesture(char x); //返回手势x能胜的手势
void winCount(char x,int *arr); //统计胜利次数
char findBest(int* arr); //返回获胜次数最多的手势,次数相同时按字母序最小的输出
int main()
{
result player[2];
int won[2][3]={{0,0,0},{0,0,0}}; //甲、乙各手势获胜次数,3个手势按 B C J排列
char p1,p2;
int caseNumber;
scanf("%d",&caseNumber);
while(caseNumber--){
getchar(); //读取上一行换行符
scanf("%c %c",&p1,&p2);
if(p1==p2) player[0].equal=++player[1].equal; //平局次数更新
else if(winGesture(p2)==p1){ //若p2胜p1
player[1].win++;
player[0].lose++;
winCount(p2,won[1]); //对乙选手各手势获胜次数更新
}
else{ //否则甲胜
player[0].win++;
player[1].lose++;
winCount(p1,won[0]);
}
}
printf("%d %d %d\n",player[0].win,player[0].equal,player[0].lose);
printf("%d %d %d\n",player[1].win,player[1].equal,player[1].lose);
printf("%c %c",findBest(won[0]),findBest(won[1]));
return 0;
}
char winGesture(char x)
{
if(x=='B') return 'C';
else if(x=='C') return 'J';
else return 'B';
}
void winCount(char x,int*arr)
{
if(x=='B') arr[0]++;
else if(x=='C') arr[1]++;
else arr[2]++;
}
char findBest(int* arr)
{
int hi=0;
if(arr[1]>arr[hi]) hi=1;
if(arr[2]>arr[hi]) hi=2;
if(hi==0) return 'B';
else if(hi==1) return 'C';
else return 'J';
}
1019. 数字黑洞
题目分析:
这题有个重要的坑点,输出的 "
“号和”
"号前后都需要空格。
思路:
根据题目的要求,主体目标基本可以确定下来,编写一个函数,传入一个值,它按题目要求输出一个等式,如果差为6174或者0(传入值各位相等),就返回0,其他情况返回新的差。那么用while循环反复调用这个函数,直到返回值是0即可。
源代码
#include <stdio.h>
int subtraction(int num); //返回传入参数按规则进行一轮计算后得到的差
int main()
{
int testValue;
scanf("%d",&testValue);
while((testValue=subtraction(testValue))!=0)
;
return 0;
}
int subtraction(int num)
{
int sub[2][4]; //储存被减数和减数
for(int i=0;i<4;++i){
sub[0][i]=num%10;
num/=10;
}
int j=1;
while(j<4){
int count=j;
while(count&&sub[0][count]>sub[0][count-1]){ //按非升序排列
int tmp=sub[0][count]; //互换
sub[0][count]=sub[0][count-1];
sub[0][count-1]=tmp;
count--;
}
j++;
}
for(int i=0;i<4;++i) //根据排好序的sub[0],逆置得到sub[1],非降序排列
sub[1][i]=sub[0][3-i];
int num1,num2;
num1=sub[0][0]*1000+sub[0][1]*100+sub[0][2]*10+sub[0][3];
num2=sub[1][0]*1000+sub[1][1]*100+sub[1][2]*10+sub[1][3];
int diff=num1-num2;
if(diff==0||diff==6174){ //若差为0,或6174,返回0,终止循环
printf("%04d - %04d = %04d",num1,num2,diff); //服了,到底时要加空格的,也不说。。
return 0;
}
printf("%04d - %04d = %04d\n",num1,num2,diff);
return diff;
}
1020. 月饼
题目分析:
题目要求实际就是按照各个商品单位重量价值的非升序来卖。思路比较简单,但是也有不少需要小心注意的细节,在WA多次之后,才渐渐完善了程序。
需要注意:除了月饼种类数可以用int储存,其他变量均需要用double,从测试情况看,测试点中有些点给出的就是double值。此外,还需要考虑到供给量小于需求量的情况,避免进入死循环(测试点3就是这种情况)。
源代码
#include <stdio.h>
struct moonCake{
double storage;
double totalPrice;
double aveProfit;
};
int main()
{
int classNum; //月饼种类数
double marketDemand; //市场需求量
scanf("%d %lf",&classNum,&marketDemand);
moonCake *warehouse=new moonCake[classNum];
for(int i=0;i<classNum;++i)
scanf("%lf",&warehouse[i].storage);
for(int i=0;i<classNum;++i){
scanf("%lf",&warehouse[i].totalPrice);
warehouse[i].aveProfit=warehouse[i].totalPrice/warehouse[i].storage;
}
int j=1;
while(j<classNum){ //按平均收益非升序排列
int count=j;
while(count&&warehouse[count].aveProfit>warehouse[count-1].aveProfit){
moonCake tmp=warehouse[count];
warehouse[count]=warehouse[count-1];
warehouse[count-1]=tmp;
count--;
}
j++;
}
double totProfit=0;
int i=0;
while(i<classNum){ //很重要,可能出现需求大于库存的情况
if(marketDemand==0) break; //需求降为0,终止循环
else if(marketDemand<warehouse[i].storage){ //市场需求量小与此类,更新收益后停止循环
totProfit+=marketDemand*warehouse[i].aveProfit;
break;
}
else{ //否则需求比当前种类储存量大
totProfit+=warehouse[i].totalPrice;
marketDemand-=warehouse[i].storage;
i++;
}
}
printf("%.2f",totProfit);
delete []warehouse;
return 0;
}
1021. 个位数统计
题目分析:
这道题没有什么特殊的考虑,也没有很特别的数据测点,相对比较容易,编程时自己注意就可以顺利AC。
不超过1000位,那么就开一个长度位1001的int型数组,按字符读取存入数组。根据各位数字来更新各个数字出现次数。最后将出现次数不为0的按序输出即可。
源代码
#include <stdio.h>
int main()
{
int num[1001];
int count=0; //记录N的位数
int digit[10];
for(int i=0;i<10;++i)
digit[i]=0;
while((num[count]=getchar())!=EOF){
num[count]-='0'; //将ASCII码转换成数字
count++;
}
for(int i=0;i<count;++i)
digit[num[i]]++;
int first=0; //第一次输出标记
for(int i=0;i<10;++i)
if(digit[i]){ //若数字i出现次数不为0
if(first) printf("\n"); //不是第一次输出,则先换行
printf("%d:%d",i,digit[i]);
first++;
}
return 0;
}
1022. D进制的A+B
题目分析:
这题主要就是栈的简单应用,利用栈后进先出的特性,将短除法的结果存入一个栈中,然后输出即可。这里栈只需要很简单的结构,创建一个数组,给一个指针。另外根据题目所给的数据范围容易知道,和可以用int存储,转换后的进制数位数不超过31位。
需要注意一点,给出的数只说是非负数,那么对输入是0,0的情况需要考虑在内。
源代码
#include <stdio.h>
int main()
{
int num[1001];
int count=0; //记录N的位数
int digit[10];
for(int i=0;i<10;++i)
digit[i]=0;
while((num[count]=getchar())!=EOF){
num[count]-='0'; //将ASCII码转换成数字
count++;
}
for(int i=0;i<count;++i)
digit[num[i]]++;
int first=0; //第一次输出标记
for(int i=0;i<10;++i)
if(digit[i]){ //若数字i出现次数不为0
if(first) printf("\n"); //不是第一次输出,则先换行
printf("%d:%d",i,digit[i]);
first++;
}
return 0;
}