2024年NOJ详解(更新中)

西北工业大学NOJ详解(更新中)

写在前面

​ 本文旨在分享有关NOJ题目的思路和做法以及注意事项(不保证我分享代码的简洁和高效),***不鼓励***同学们直接Copy代码。希望大家在读完本文后能够有所收获,也希望同学们能够对我其中的错误进行指正。发布顺序不固定。其中发布的代码均已确认AC。

小建议:推荐大家可以尝试使用Clion这个IDE,在纠正代码错误方面十分好用。以及Snipaste截图软件,可以把截图始终显示在屏幕最上方,不必再来回看题。

关于NOJ

​ NOJ是西北工业大学开设的C语言实验课的作业,同时也是上课的主要内容。60题AC是报名期末考试的条件。但个人觉得其中部分题目难度过于大了,而这部分难度不是体现在编程上,反而体现在数学上,这也是我个人想进行题目解析和分享的一个原因。

详解

001 Hello World

001题面

#include <stdio.h>

int main(void) {
    printf("Hello World");
    return 0;
}

​ printf函数用法(部分软件初始代码就是“Hello World”(笑))

002 A+B

002.1

002.2

#include <stdio.h>

int main(void) {
    int a,b;
    scanf(" %d %d",&a,&b);
    printf("%d",a+b);
}

这题就是简单的输入和输出,入门题。没什么需要讲的。

003 数据类型大小及范围

003.1

003.2

#include <stdio.h>
#include <limits.h>

int main()
{
    int i,a=0;
    scanf(" %d",&i);
    switch(i)
    {
        case(1):{
            printf("%llu,%d,%d",sizeof(char),CHAR_MIN,CHAR_MAX);//sizeof返回类型为unsigned long long
            break;
        }
        case(2):{
            printf("%llu,%d,%d",sizeof(unsigned char),a,UCHAR_MAX);
            break;
        }
        case(3):{
            printf("%llu,%d,%d",sizeof(short),SHRT_MIN,SHRT_MAX);
            break;
        }
        case(4):{
            printf("%llu,%d,%d",sizeof(unsigned short),a,USHRT_MAX);
            break;
        }
        case(5):{
            printf("%llu,%d,%d",sizeof(int),INT_MIN,INT_MAX);
            break;
        }
        case(6):{
            printf("%llu,%d,%d",sizeof(unsigned int),a,UINT_MAX);
            break;
        }
        case(7):{
            printf("%llu,%ld,%ld",sizeof(long),LONG_MIN,LONG_MAX);
            break;
        }
        case(8):{
            printf("%llu,%d,%lu",sizeof(unsigned long),a,ULONG_MAX);
            break;
        }
        case(9):{
            printf("%llu,%lld,%lld",sizeof(long long),LLONG_MIN,LLONG_MAX);
            break;
        }
        case(10):{
            printf("%llu,%d,%llu",sizeof(unsigned long long),a,ULLONG_MAX);
            break;
        }
        default:return 0;
    }
    return 0;
}

思路:c语言中<limits.h>头文件中存储着各字符类型的大小范围,可以通过调用这个头文件再加上sizeof()函数,通过switch…case语句就可以实现题目要求。注意:<limits.h>头文件中没有unsigned …类型的最小值,其最小值就是0。另外:sizeof()函数返回值类型为unsigned long long,虽然这里当成int应该也可以AC

注意数据类型。例如:不要把ULLONG_MAX用%d输出,这样会无法得到正确结果。

004 平均值

004.1

004.2

#include <stdio.h>

int main(void) {
    long long a,b;
    scanf( " %lld %lld",&a,&b);
    printf("%lld",(a+b)/2);
    return 0;
}

注意:这题若将a,b类型定义为int,则会显示WA,将其定义为long long则是AC。这题只有这点需要特别提出。

005 进制转换

005

#include <stdio.h>

int main(void) {
    int n;
    scanf(" %d",&n);
    printf("%X,%o",n,n);
    return 0;
}

注意:其中十六进制中的字母为大写。

这题考察格式化输出十六进制和八进制,分别用%X和%o就可以实现十进制向十六进制和八进制的转换。(若是%x则输出十六进制的字母为小写)

006 浮点数输出

005

#include <stdio.h>

int main(void) {
    long double n;
    scanf(" %Lf",&n);//l是大写
    printf("%.6Lf,%.2Lf,%.8Lf",n,n,n);
    return 0;
}

考查格式化输出小数点后位数。

虽然若是考虑到精度问题,这里使用long double更为合适,但使用double也可以AC。其中注意:输出long double类型需要使用%Lf,l采用大写形式。

007 动态宽度输出

007

#include <stdio.h>

int main(void) {
    int m,n,k=1;//k用来统计m的位数
    scanf(" %d %d",&m,&n);
    int cy=m;//复制m的值
    while(cy/=10)
        k++;
    if(n<=k)
        printf("%d",m);
    else{
        for(int i=0;i<(n-k);i++)
            printf("0");
        printf("%d",m);
    }
    return 0;
}

注意:这里没有提及的是,当m宽度大于或等于n时,输出m本身。

思路:先统计m的位数k(将其不断/10,直至为0,每次k+1),再将其与n进行比较,若是位数大于等于n,则输出m;否则,在前面输入n-k个0,再输出m。

008 计算地球上两点之间的距离

008.1

008.2

#include<stdio.h>
#include<math.h>
double hav(long double a);
int main()
{
    double a1,a2,b1,b2,c,d,pi=3.14159265;//pi值要足够精确
    scanf(" %lf %lf %lf %lf",&a1,&a2,&b1,&b2);
    c=hav((b1-a1)/180*pi)+cos(a1/180*pi)*cos(b1/180*pi)*hav((b2-a2)/180*pi);
    d=acos(1-2*c)*6371;
    printf("%.4lfkm",d);
    return 0;
}
double hav(long double a)
{
    double b=(1-cos(a))/2;
    return b;
}

注意:这题计算需要用弧度而不是角度,因此经度纬度都需要先换算成相应的弧度,才能进行计算。其中π值需要自己设置,要尽量精确。

思路
由 H a v e r s i n e 公 式 计 算 出 c = h a v ( d r ) 的 值 。 由 h a v ( θ ) = 1 − c o s ( θ ) 2 , 转 化 为 c o s ( θ ) = 1 − 2 h a v ( θ ) , 即 d r = cos ⁡ − 1 ( 1 − 2 c ) 则 d = r cos ⁡ − 1 ( 1 − 2 c ) 由Haversine公式计算出c=hav(\frac{d}{r})的值。\\由hav(\theta)=\frac{1-cos(\theta)}{2},转化为cos(\theta)=1-2hav(\theta),\\即\frac{d}{r}=\cos^{-1}(1-2c)\\则d=r\cos^{-1}(1-2c) Haversinec=hav(rd)hav(θ)=21cos(θ)cos(θ)=12hav(θ)rd=cos1(12c)d=rcos1(12c)

072 【专业融合:动能】热能计算

072(0)

072(1)

072(2)

#include <stdio.h>

int main(void) {
    double ti,tf,m1,c1,m2,c2;
    //ti为初始温度,tf为加热后温度,m1、m2分别为液体和容器质量,c1、c2为热能百分比
    scanf(" %lf%lf%lf%lf%lf%lf",&ti,&tf,&m1,&c1,&m2,&c2);
    double q1=c1*m1*(tf-+ti),q2=c2*m2*(tf-ti);
    //q1、q2分别为液体和容器所需要的热量
    printf("%.2lfkJ,%.2lf%%,%.2lf%%\n",(q1+q2)/1000.0,(q2/(q1+q2)),(q1/(q1+q2)));
    return 0;
}

AC需要注意的是kJ,k小写,J大写。还有输出顺序,先容器后液体。虽然是液体先被输入(笑)。

题目错误:热能百分比样例输出错误,加上了%却没有✖️100。但若是加上这步操作,则为WA

073 成绩单

73.1

73.2

#include <stdio.h>
#include "stdlib.h"
#include "string.h"

struct tagStudent{//定义一个结构体,照着题目做就行
    char id[11];
    char name[31];
    int score;
};

void sequence(struct tagStudent **ppST,int n);//排序函数,对成绩进行排序

int main(void) {
    int n;
    scanf(" %d",&n);
    struct tagStudent **ppST=(struct tagStudent**)malloc(n*sizeof(struct tagStudent*));
    //定义结构体双指针
    for(int i=0;i<n;i++){ //共n次循环,写入数据,同时分配堆
        ppST[i]=(struct tagStudent*) malloc(sizeof(struct tagStudent));
        scanf(" %s %s %d",ppST[i]->id,ppST[i]->name,&ppST[i]->score);
    }
    sequence(ppST,n); //对其排序
    for(int i=0;i<n;i++){//依次打印到屏幕
        printf("%s %s %d\n",ppST[i]->id,ppST[i]->name,ppST[i]->score);
    }
    for(int i=0;i<n;i++){
        free(ppST[i]);//依次释放堆
        ppST[i]=NULL;//赋初值
    }
    free(ppST);
    ppST=NULL;
    return 0;
}

void sequence(struct tagStudent **ppST,int n){
    struct tagStudent *temps;
    int logEqual;//用来记录有几个数相等
    int len= strlen(ppST[0]->id);//获取学号位数,后面比较学号会用到
    for(int i=0;i<(n-1);i++){//依次比较分数,若后面大于前面,则交换
        for(int j=i+1;j<n;j++){
            if(ppST[i]->score<ppST[j]->score){//比较分数
                temps=ppST[i];
                ppST[i]=ppST[j];
                ppST[j]=temps;
            }
        }
    }
    //已按照分数实现排序
    for(int i=0;i<(n-1);i++){//依次比较前后分数是否相等
        logEqual=1;
        if(ppST[i]->score!=ppST[i+1]->score)//如果不相等直接进行下一次比较
            continue;
        for(int j=i+1;j<(n-1);j++){//相等则继续判断之后是否依然相等
            if(ppST[j]->score==ppST[j+1]->score)
                logEqual++;//计数有几个相等的分数
            else break;//不相等则停止计数
        }
        int cy=i;//复制此时i的值
        for(;i<(cy+logEqual);i++){//如上面算法相似,比较学号,后面比前面小则交换
            for(int j=(i+1);j<(cy+logEqual+1);j++){
                for(int m=0;m<len;m++){//比较第(i+1)个和第(j+1)的学号的大小,从大位到小位比较
                    if(ppST[i]->id[m]>ppST[j]->id[m]){//字符会转化为ASCII码序号进行比较
                        temps=ppST[i];
                        ppST[i]=ppST[j];
                        ppST[j]=temps;
                        break;//比较出一位即可不再比较
                    }
                    else if(ppST[i]->id[m]<ppST[j]->id[m])
                        break;//比较出一位即可不再比较
                }
            }
        }
    }
    temps=NULL;//因为没有给temps分配堆,故不需要释放堆,若释放则会出现乱码
}

思路:先排成绩,再在成绩相同的结构体中排学号。其中定义结构体双指针,使得可以在之间进行地址的交换,从而实现交换数据。

注意

1.在交换地址时所使用的中间指针,由于没有分配堆,不需要进行内存释放。

2.在进行比较的时候,不要忽略使用break。若是忽视其中一个break就会导致结果出错,因为会出现过多比较的情况。比如:学号之间比较时,只要有一位不同就可以停止比较了,否则会进行下面位次的比较,导致出错。

字符串比较大小:这题需要学号之间进行比较,而字符串之间比较大小可以采用每个字符依次比较。字符在比较的时候会转化为ASCII码序号进行比较。比如字符‘0’会转化为数字48,‘1’转化为49。因此可以比较。此外:可以不按照题目提示,将学号的类型定义为long long,应该也能行得通。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值