1023. 组个最小数
题目分析:
这道题没有遇到需要额外注意的坑。要求组成的数字尽量小,那么第一位应该是非0的且出现过的最小数字,之后再从0开始,若该位出现次数不为0,则输出,一直遍历到9。
编程的时候有个地方要注意,输出了最高位之后,要记得把储存该位数字出现的次数相应减1。
源代码
#include <stdio.h>
int main()
{
int digit[10]; //储存各个数字的个数
int num[50]; //储存生成的数字
for(int i=0;i<10;++i) scanf("%d",&digit[i]);
for(int i=1;i<10;++i)
if(digit[i]){
num[0]=i; //找到非0的最低位作为首位
digit[i]--; //相应剩下数字个数-1
break;
}
int count=1; //记录生成数的位数
for(int i=0;i<10;++i){ //从最小数开始
while(digit[i]--) //当该位数不为0
num[count++]=i;
}
for(int i=0;i<count;++i)
printf("%d",num[i]);
return 0;
}
1024. 科学计数法
题目分析:
细节比较多,但没有额外的数据测例和格式上的坑。耐心+细心就能顺利AC。
在保存各位有效数字的时候,直接开数组保存各位有效数字即可,不必保存小数点,因为第一位必是整数位,后面全是小数位。
在输出时,需要根据各种情况进行判断。
- 指数大于等于小数位数:无小数点。
- 指数不够小数位数,但指数大于-1:整数位不为0,输出相应整数位后打印小数点,再输出剩下的位数
- 指数小于0:前面两种情况下,有效数字第一个元素都输出了,这种情况下有效数字都还没输出,另外还需考虑前面补零的情况,补充零的个数=1-exp (exp指存储的指数值)
源代码
#include <stdio.h>
int main()
{
char numSymbol; //储存数字和指数的符号
numSymbol=getchar();
char *digit=new char[10000]; //储存各个有效数字
digit[0]=getchar();
getchar(); //读取并丢弃小数点
int count=1; //记录数字总位数
while((digit[count++]=getchar())!='E'); //直到遇到符号E
count--; //丢弃字符E,存储的小数位数为count-1
int exp;
scanf("%d",&exp); //读取指数
if(digit[0]=='0'){ printf("0");return 0;} //若首位为0,输出0
if(numSymbol=='-') printf("-"); //若是负数且首位不为0,打印符号
if(exp>=count-1){ //若实际是整数
for(int i=0;i<count;++i)
printf("%c",digit[i]);
for(int i=0;i<exp-count+1;++i)
printf("0"); //剩余指数补0
}
else{ //否则是小数
if(exp>-1){ //整数部分非0
int intDigit=exp+1; //普通表示法下整数位数
for(int i=0;i<intDigit;++i) //输出整数部分
printf("%c",digit[i]);
printf(".");
for(int i=exp+1;i<count;++i) //剩余小数
printf("%c",digit[i]);
}
else{ //否则整数位为0
int extraZero=-exp-1; //小数点后需补上的的0个数
printf("0.");
for(int i=0;i<extraZero;++i)
printf("0");
for(int i=0;i<count;++i)
printf("%c",digit[i]);
}
}
delete []digit;
return 0;
}
1025. 反转链表
题目分析:
题目乍看起来比较麻烦,虽说是链表,但肯定不能用链表来写,只是套用了链表的思想。但是注意到题目所给的内存限制非常宽松,为了加快查找速度,应该选择trade memory for speed,开一个大数组存储各个结点,采用随机访问的方式来缩短寻址时间。
这里我用了结构体来表示各个结点,成员包括了地址、数据和下一元素的地址。
在反转链表时,可以直接用algorithm头文件中的reverse函数,这个函数需要提供起始位置和终止位置,其工作原理就是从第一个元素开始反复调用swap(begin+i,end-i)。还有一个简化代码的策略,不要去修改反转后的每个结点对应的下一元素变量的值,在输出本节点对应的下一结点地址时不使用本结点的成员next,而直接用下一结点的成员address来输出。这样对于最后一个元素未被换位置时显然可行,但对于最后一个元素恰好被调换位置的情况似乎会出现问题。为了解决这个麻烦,可以在循环输出时留下最后一个元素,在输出最后一个元素的下一结点地址时直接输出-1即可。
源代码
#include <stdio.h>
#include <algorithm>
struct linkNode
{
int _address,_data, _next;
};
int main()
{
linkNode* nodeArray=new linkNode[100000]; //牺牲一些空间,采用随机访问方式
int head,nodeNumber,gap; //首节点地址、结点数、反转步长
scanf("%d %d %d",&head,&nodeNumber,&gap);
linkNode* linkList=new linkNode[nodeNumber];
int address;
for(int i=0;i<nodeNumber;++i){
scanf("%d",&address);
nodeArray[address]._address=address;
scanf("%d %d",&nodeArray[address]._data,&nodeArray[address]._next);
}
int count=0; //统计链表中的数字个数,可能存在某些元素不在链表中的情况
int next=head;
while(next!=-1){
linkList[count++]=nodeArray[next];
next=nodeArray[next]._next;
}
for(int i=0;i<(count-count%gap);i+=gap) //对若干组长度符合要求的进行逆序
std::reverse(linkList+i,linkList+i+gap);
for(int i=0;i<count-1;++i) //交换后唯一需要修改输出的就是下一元素地址,这里不改变结构体的值,直接输出物理上下一元素地址即可
printf("%05d %d %05d\n",linkList[i]._address,linkList[i]._data,linkList[i+1]._address);
printf("%05d %d -1",linkList[count-1]._address,linkList[count-1]._data);
delete[]nodeArray;
delete[]linkList;
return 0;
}
1026. 程序运行时间
题目分析:
相比前面的两道题这题要容易不少,考虑好四舍五入方法得到正确的秒数后,剩下的问题就能迎刃而解。
计算秒数首先要注意要显式将时间差转化成double型再除以10,否则编译器会认为是整型除法,计算得到整数结果再扩展成double值,那么这个double表示的还是一个整数。
为了实现四舍五入,直接转换成int肯定不行,这样只是单纯丢弃小数部分。可以用准确的double值减去转换成整形的int值,二者的差乘以2再转换成int,用代码表示为:
double realSecond; //计算得到的准确的秒数
int second=realSecond; //截断得到的不精确秒数
second+=(int)2*(realSecond-second); //四舍五入后的秒数
源代码
#include <stdio.h>
int main()
{
int clock1,clock2;
scanf("%d %d",&clock1,&clock2);
int diff=clock2-clock1;
double rawSeconds=(double)diff/100;
int seconds=rawSeconds; //转换成秒数
seconds+=(int)2*(rawSeconds-seconds); //四舍五入
int hour=seconds/3600;
seconds=seconds%3600;
int minute=seconds/60;
seconds=seconds%60;
printf("%02d:%02d%02d",hour,minute,seconds);
return 0;
}
1027. 打印沙漏
题目分析:
这题有个大坑点:千万不要输出符号右边的空格,即每行左边按要求空格之后输出完符号就换行。
抛开这个坑,剩下就是分析清楚数学关系,根据题目的条件容易分析得到单侧沙漏各层数据为一个等差数列,假设从第一层到中间一个符号共有n层,那么整个沙漏消耗的符号数为:
N
u
m
=
2
∗
[
1
+
3
+
5
+
.
.
.
+
(
2
n
−
1
)
]
−
1
=
2
n
2
−
1
Num=2*[1+3+5+... +(2n-1)]-1=2n^2 -1
Num=2∗[1+3+5+...+(2n−1)]−1=2n2−1
根据这个式子循环遍历寻找能够消耗的最大符号数,那么就可以求出层数以及剩下的未用符号数量。
根据格式,计算好每一行要输出的空格个数和符号个数,输出即可。
源代码
#include <stdio.h>
int main()
{
int num;
char symbol;
scanf("%d %c",&num,&symbol);
int count=0; //统计最多能组成沙漏数的n值
int sandNumber=1;
while(sandNumber<=num){
count++;
sandNumber=2*(count+1)*(count+1)-1;
}
int left=num-(2*count*count-1); //剩余未用符号数量
int halfLevel=count-1; //对称部分层数
int width=2*halfLevel+1; //输出宽度
int tmp=halfLevel;
while(tmp){ //上半部分
int len=2*tmp+1;
int space=(width-len)>>1; //输出空格数
for(int i=0;i<space;++i) printf(" ");
for(int i=0;i<len;++i) printf("%c",symbol);
printf("\n"); //换行
tmp--;
}
for(int i=0;i<=halfLevel;++i){ //下半部分
int len=1+2*i;
int space=(width-len)>>1;
for(int j=0;j<space;++j) printf(" ");
for(int j=0;j<len;++j) printf("%c",symbol);
printf("\n"); //换行
}
printf("%d",left);
}
1028. 人口普查
题目分析:
有两点需要注意,不算坑,确实是稳健的代码所需要考虑到地方,也是我几次失败修反复修改测试才发现:
- 即使年纪最大的人就是年纪最轻的人,也要把名字都输出出来,而不能只输出一遍。
- 输入可能没有符合要求的人,这时候输出0即可
为了保存信息,我采用了一个结构体,存储姓名、出生年、月、日。
之后在判断人数和寻找年龄最大最小者时,我采用的方法是,先把所有输入信息存入数组,然后按照年龄降序进行排序。之后再遍历,找到的第一个年龄符合要求的人即是年龄最大者,最后一个年龄符合要求的人即是年龄最小者。排序算法建议采用algorithm头文件里的sort函数,自己编写一个判断函数做第三个参数即可,比自己手撸方便多了。
不过这种方法在没有人生日有效的情况下需要注意判断。
源代码
#include <stdio.h>
#include<algorithm>
using namespace std;
struct info
{
char _name[6];
int _year,_month,_day;
};
bool cmp(const info &p1,const info& p2);
int main()
{
int num;
scanf("%d",&num);
info *person=new info[num];
int count=0; //记录生日有效人数
for(int i=0;i<num;++i) {
scanf("%s %d",person[i]._name,&person[i]._year);
getchar(); //读取丢弃"/"
scanf("%d",&person[i]._month);
getchar();
scanf("%d",&person[i]._day);
}
sort(person,person+num,cmp); //按年龄降序序排列
int i=0;
while(person[i]._year<=1814&&i<num){
if(person[i]._year==1814){
if(person[i]._month>9) break;
else if(person[i]._month==9&&person[i]._day>=6) break;
}
i++;
} //循环结束时i对应的即为年龄最大者,也可能仍然非有效年龄
int old=i;
if(i<num){
while(person[i]._year<=2014&&i<num){ //寻找年龄最小者
if(person[i]._year==2014){
if(person[i]._month>9) break; //未出生
else if(person[i]._month==9&&person[i]._day>6) break;
}
count++;
i++;
}
}
if(count)printf("%d %s %s",count,person[old]._name,person[i-1]._name); //不论二者是不是同一个人,均输出其名字
else printf("0");
return 0;
}
bool cmp(const info &p1,const info& p2)
{
if(p1._year!=p2._year) return p1._year<p2._year; //按年龄降序排列,因此年月日升序
if(p1._month!=p2._month) return p1._month<p2._month;
return p1._day<p2._day;
}