2 条题解

  • 2
    @ 2023-10-2 14:08:34

    来讲讲做题中容易出现的问题。

    首先对于这道题我个人的做法是使用结构体+排序的思路。 目前我遇到的问题都是出在 cmp 函数上,在本题解的讲解也围绕 cmp 函数展开,请使用其它方法的同学们自行类比(反正各种解法其实几乎都是换汤不换药)。

    本人是以 60-70-40-50-90 的顺序错了一圈的,很有经验。

    (本帖又名:我的错误之路)


    首先让我们看看我的结构体定义:

    struct stu{
    	int id;//学号
    	int sc;//总分数
    	int ch;//语文成绩
    }
    

    (不看这个你是看不懂下文的)

    然后来说说问题所在。

    1

    60 分的问题。

    这里贴上错误代码:

    bool cmp(stu a,stu b){
    	if(a.sc==b.sc)return a.id>b.id;
    	return a.sc>b.sc;
    }
    

    这种错法应该出现比较少。

    如果出现这种错误,只能说你有些太粗心了。(但这是我犯的QWQ)

    你在忽视了需在依据学号排序前依据语文成绩排序的同时,还把学号的大小于号写反了欸!

    2

    现在说 70 分,下面贴出 cmp 函数的代码:

    bool cmp(stu a,stu b){
    	if(a.sc==b.sc)return a.id<b.id;
    	return a.sc>b.sc;
    }
    

    这时建议你多读几遍题目

    你甚至忽视了需在依据学号排序前依据语文成绩排序

    3

    之后是 40 分。

    3,2,1,上代码!

    bool cmp(stu a,stu b){
    	if(a.sc==b.sc)return a.ch>b.ch;
    	if(a.ch==b.ch)return a.id<b.id;
    	return a.sc>b.sc;
    }
    

    这个问题出现应相对较少,但它也是最难发现的问题之一。

    在这段代码中,第二个 if 语句不会被运行,对于语文成绩相等的情况,会在第一个 if 语句后返回 false

    对于这个问题,应在第一个 if 语句中加入对于语文成绩是否相等的判断。

    4

    50 分的场合

    bool cmp(stu a,stu b){
    	if(a.sc==b.sc&&a.ch!=b.ch)return a.ch>b.ch;
    	if(a.ch==b.ch)return a.id<b.id;
    	return a.sc>b.sc;
    }
    

    和 40 分的错误性质类似,同样难以发现。

    判断语文应该是在总分相等的前提下。

    5

    最后说 90 分,代码:

    bool cmp(stu a,stu b){
    	if(a.sc==b.sc&&a.ch!=b.ch){
    		return a.ch>b.ch;
    		if(a.ch==b.ch&&a.id!=b.id)return a.id<b.id;
    	}return a.sc>b.sc;
    }
    

    这种情况,首先因为里面那层 ifa.ch==b.ch 会被外面那层 if 筛掉,所以应首先删掉外面那层 if 的第二条判断条件;

    然后把外面那层 if 语句里两条语句交换位置就行了。


    最后,贴上正确的 cmp 函数代码:

    bool cmp(stu a,stu b){
    	if(a.sc==b.sc){
    		if(a.ch==b.ch&&a.id!=b.id)return a.id<b.id;
    		return a.ch>b.ch;
    	}return a.sc>b.sc;
    }
    

    完整代码:

    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    struct stu{
    	int id;
    	int sc;
    	int ch;
    }a[314]={0};
    bool cmp(stu a,stu b){
    	if(a.sc==b.sc){
    		if(a.ch==b.ch&&a.id!=b.id)return a.id<b.id;
    		return a.ch>b.ch;
    	}return a.sc>b.sc;
    }
    int main(){
    	int n,c,m,e;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d%d%d",&c,&m,&e);
    		a[i].id=i;
    		a[i].ch=c;
    		a[i].sc=c+m+e;
    	}
    	sort(a+1,a+n+1,cmp);
    	for(int i=1;i<=5;i++)
    		printf("%d %d\n",a[i].id,a[i].sc);
        return 0;
    }
    

    总结:我在做这题时脑子糊掉了。

    (80 分那次是帮别人调代码)(目前还没调出来,希望好心人帮帮忙

    记得五星好评哦喵~ 谢谢客官啦~

    • -1
      @ 2023-8-9 17:56:48

      可以在快排那个过程上多加一个变量k,用来表示当前的快排使用的关键字是什么,1表示以总分为关键字,2表示以语文为关键字,3表示以学号为关键字。都是从小到大排序。

      在以总分为关键字排完一遍后,找到总分相同的一些连续位置,将这些位置上的数再以语文为关键字再排一遍,然后再找到连续的总分,语文成绩都相同的位置,将这些位置上的数再以学号为关键字从小到大排。

      代码呈现

      #include<cstdio>
      #include <stdlib.h>
      int n,a[20000][4]; 
      void kp(int l,int r,int k){
          int i = l,j = r,m = a[(i+j)/2][k];
          do
          {
              while (a[i][k] < m) i++;
              while (m < a[j][k]) j--;
              if (i <= j)
              {
                  a[0][1] = a[i][1];
      			a[i][1] = a[j][1];
      			a[j][1] = a[0][1];
                  a[0][2] = a[i][2];
      			a[i][2] = a[j][2];
      			a[j][2] = a[0][2];
                  a[0][3] = a[i][3];
      			a[i][3] = a[j][3];
      			a[j][3] = a[0][3];
                  i++;j--;
              }
          }while (i <= j);
          if (l < j) kp(l,j,k);
          if (i < r) kp(i,r,k);
      }
      void input_data(){
          scanf("%d",&n);
          for (int i = 1;i <= n;i++)
              {
                  int x,y,z;
                  scanf("%d%d%d",&x,&y,&z);
                  a[i][1] = x + y + z;
                  a[i][2] = x;
                  a[i][3] = i;
              }
          kp(1,n,1);
          int i = 1;
          while (i <= n)
              {
                  int j = i+1;
                  while (a[i][1] == a[j][1]) j++;
                  kp(i,j-1,2);
                  i = j;
              }
          i = 1;
          while (i <= n) 
              {
                  int j = i+1;
                  while (a[i][1] == a[j][1] && a[i][2] == a[j][2]) j++;
                  kp(i,j-1,3);
                  i = j;
              }
      }
      void output_ans()
      {
          for (int i = n;i >= n-4;i--)
              printf("%d %d\n",a[i][3],a[i][1]);
      }
      int main(){
          input_data();
          output_ans();
          return 0;
      }
      
      • 1

      信息

      ID
      446
      时间
      1000ms
      内存
      125MiB
      难度
      5
      标签
      递交数
      39
      已通过
      15
      上传者