胡凡 《算法笔记》 上机实战训练指南 3.1 简单模拟

Posted 临风而眠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了胡凡 《算法笔记》 上机实战训练指南 3.1 简单模拟相关的知识,希望对你有一定的参考价值。

胡凡 《算法笔记》 上机实战训练指南 3.1

持续更新中 , 菜鸡的刷题笔记…

大学到现在了还没咋好好刷过题,该push自己了…

文章目录

3.1 简单模拟

【PAT B1001】害死人不偿命的(3n+1)猜想

  • 题目链接

  • AC代码

    #include <iostream>
    using namespace std;
    int main() 
      int n;
      scanf("%d",&n);
      int res;
      int step = 0;
      while( n != 1)
      
        if(n % 2 == 0)
        
          n /= 2;
        
        else
        
          n = ( 3 * n + 1) / 2;
        
        step += 1;
      
    
      cout << step;
      return 0;
    
    
  • 简洁写法

    if (n % 2) 
                n = (n * 3 + 1) / 2;
             else 
                n /= 2;
            
    

【PAT B1032】挖掘机技术哪家强

  • 题目链接

  • 一开始的代码

    • 只过了一个测试点
    #include <cstdio>
    int score[10010]=0;
    int main()
    
        int N;
        scanf("%d",&N);
        
        int maxScore;
        int index,num;
        int residx ;
        for(int i = 1; i <= N; i ++)
        
            scanf("%d%d",&index,&num);
            score[index]+=num;
        
        maxScore = score[1];
        for (int i = 2; i <= N; i ++)
        
            if(score[i] > maxScore)
            
                maxScore = score[i];
                residx = i;
            
        
        printf("%d %d",residx,score[residx]);
        return 0;
    
    
  • 上面的代码的漏洞在于,如果第一个学校的总分就是最高的,无法输出

  • 于是,将自己的代码里面的 residx初始化为1,但还是有数据点没通过

  • 看了半天,不知道为啥错,仔细一看,数组开小了…

    • 10的5次方… 就开了个10010… 蚌埠住了… 这里浪费了一堆时间
  • AC代码

    #include <cstdio>
    int score[100010];
    int main()
    
        int N;
        scanf("%d",&N);
        
        int maxScore;
        int index,num;
        int residx = 1;
        for(int i = 1; i <= N; i ++)
        
            scanf("%d%d",&index,&num);
            score[index]+=num;
        
        maxScore = score[1];
        for (int i = 1; i <= N; i ++)
        
            if(score[i] >= maxScore)
            
                maxScore = score[i];
                residx = i;
            
        
        printf("%d %d",residx,score[residx]);
        return 0;
    
    
  • 另外,自己写的代码 两个for循环其实可以合并 ,就像题解里面只写了一个while循环那样

    #include <cstdio>
    int score[100010];
    int main()
    
        int N;
        scanf("%d",&N);
        
        int maxScore=0;
        int index,num;
        int residx = 1;
        for(int i = 1; i <= N; i ++)
        
            scanf("%d%d",&index,&num);
            score[index]+=num;
            if(score[i] > maxScore)
            
                maxScore = score[i];
                residx = i;
            
        
      
        printf("%d %d",residx,score[residx]);
        return 0;
    
    

【PAT B1011】A+B 和 C

  • 题目链接

  • AC代码

    #include <iostream>
    using namespace std;
    
    int main()
    
        int T;
        long long A,B,C;
        cin >> T;
        int i=1;
        while(T--)
        
            
            cin>> A >> B >> C;
            if(A + B > C)
                cout<<"Case #"<<i<<": true"<<endl;
            else
                cout<<"Case #"<<i<<": false"<<endl;
            i+=1;
        
        return 0;
    
    

【PAT B1016】部分A+B

  • 题目链接

  • AC代码

    #include <iostream>
    using namespace std;
    
    int getN(int a, int b)
    
        int p = 0;
        int num = 1;
        while(a)
        
            if( a % 10 == b)
            
                p += num*b;
                num *= 10;
            
            a /= 10;
        
        return p;
    
    
    int main()
    
        int A,D_A,B,D_B;
        int P_A=0,P_B=0;
        cin >> A >> D_A >> B >> D_B;
        int numA=1;
        int numB=1;
        P_A = getN(A,D_A);
        P_B = getN(B,D_B);
        cout<< P_A + P_B <<endl;
        return 0;
    
    

【PAT B1026】程序运行时间

  • 题目链接

  • 思路比较顺畅,但是一开始的答案格式错了,时分秒的输出要保证不足两位时高位用0 补充

    • 错误格式代码

      #include <iostream>
      using namespace std;
      
      int main()
      
          int C1, C2;
          cin >> C1 >> C2;
          double S = (C2-C1)/100.0;
          int T;
          int hh, mm , ss;
          if(S < (C2-C1)/100+0.5)
          
              T = (C2-C1) / 100; 
          
          else
          
              T = (C2-C1) / 100 + 1;
          
          hh = T / 3600;
          mm = T / 60 -  hh * 60;
          ss = T - hh * 3600 - mm * 60;
          printf("%d:%d:%d",hh,mm,ss);
          
          
      
      
    • 正确AC代码

      #include <iostream>
      using namespace std;
      
      int main()
      
          int C1, C2;
          cin >> C1 >> C2;
          double S = (C2-C1)/100.0;
          int T;
          int hh, mm , ss;
          if(S < (C2-C1)/100+0.5)
          
              T = (C2-C1) / 100; 
          
          else
          
              T = (C2-C1) / 100 + 1;
          
          hh = T / 3600;
          mm = T / 60 -  hh * 60;
          ss = T - hh * 3600 - mm * 60;
          printf("%02d:%02d:%02d",hh,mm,ss);
          
      
      
  • 但感觉自己的代码还是不够简洁

    这是参考链接里面那位知乎博主写的

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    int main()
    
        int C1, C2;
        cin >> C1 >> C2;
        int time = round((C2 - C1)/100.0);
        printf("%02d:%02d:%02d\\n",time/3600,time%3600/60,time%60);
     
        
    
    

    这本书上给的答案👇

    书上避免浮点数运算的写法: C2-C1的末两位不少于50时,说明除以100后需要进位

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    int main()
    
        int C1, C2;
        cin >> C1 >> C2;
        int ans = C2 - C1;
        if( ans % 100 >= 50)
        
            ans = ans / 100 + 1;
        
        else
        
            ans = ans / 100;
        
    //     int time = round((C2 - C1)/100.0);
        printf("%02d:%02d:%02d\\n",ans /3600,ans %3600/60,ans%60);
     
        
    
    

【PAT B1046】划拳

  • 题目链接

  • AC代码

    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    void getCount(int jha, int jhu, int yha, int yhu,int& jf , int& yf)
    
        if((jhu == jha + yha)&&(yhu == jha + yha) || (jhu != jha + yha)&&(yhu != jha + yha))
           return;
        else
        
           if(jhu == jha + yha)
            yf += 1;
           if(yhu == jha + yha)
            jf += 1;
         
        
        
    
    
    int main()
    
        int N;
        int jha,jhu,yha,yhu;
        int jf = 0 , yf = 0;
        cin >> N;
        while(N--)
        
            cin >> jha >> jhu >> yha >> yhu;
            getCount(jha,jhu,yha,yhu,jf,yf);
            
        
        cout<<jf<<" "<<yf;
        return 0;
    
    

    想到引用不错,但还是感觉自己写的有点复杂

  • 书上答案👇比较简洁

    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    int main()
    
        int N; //条数
        cin >> N;
        int failA, failB; //输的次数
        for(int i = 0 ;i < N ; i++)
        
            int a1,a2 ,b1, b2;
            cin>> a1 >> a2 >> b1 >> b2;
            //甲猜中乙没有猜中
            if(a1 + b1 == a2 && a1 + b1 !=b2)
            
                failB++;
            
            //甲没猜中乙猜中了
            else if( a1 + b1 != a2 && a1 + b1 == b2)
            
                failA ++;
            
            
        
        cout << failA << " " << failB;
        
        return 0;
    
    

    既然平局不加分,那就直接表示一个人赢的情况,代码更简洁

【PAT B1008】数组元素循环右移问题

  • 题目链接

  • AC居然搞了大半天…

    一开始只用一个数组的方法想了大半天… 然后开一个数组的也耗费大半天…(不过其实违背题意了…题目里说不允许使用另外数组的前提下) 因为一开始数组a从i=1开始搞的…

    #include <iostream>
    using namespace std;
    int N;
    int M;
    int a[110];
    int b[110];
    int main()
    
        cin >> N >> M;
        for(int i = 0; i <= N-1; i ++)
        
            cin >> a[i];
            
        
    //     int temp;
    //     for(int i = 1; i <= N; i ++)
    //     
    //         temp = a[i];
    //         a[i] = a[(i+M)%N];
    //         a[(i+M)%N] = temp;
    //     
        for(int i = 0; i <= N-1; i ++)
        
            b[(i+M)%N ] = a[i];
        
        //temp = a ;  a = b; b = temp;
        for(int i = 0; i <= N-2; i ++)
        
            cout << b[i] << " ";
        
        cout << b[N-1];
        return 0;
    
    
  • 知乎博主的做法

    思路nb… 启发很大

    【PAT B1008】数组元素循环右移问题 - Chilan Yuk的文章 - 知乎 https://zhuanlan.zhihu.com/p/398355139

    #include <iostream>
    using namespace std;
    
    int main()
    
        int N, M;
        int arr[105];
        cin >> N >> M;
        for(int i = 0; i < N; i ++) cin >> arr[(i+M)%N];
        cout << arr[0];
        if(N > 1) for(int i = 1; i < N; i ++) cout << " " << arr[i];
        
    
    
  • 书上的思路

    其实也是只管输出就行, cnt与N比较大小是用来控制格式

    cnt记录已经输出的数的个数

    右移M位,就相当于N-M号元素变成了新数组的第一个元素

    于是先输出N-M到N-1号元素,再输出0到N-M-1号即可

    #include <iostream>
    using namespace std;
    
    int main()
    
        
        int a[110];
        int N, M, cnt = 0;
        cin >> N >> M;
        M = M % N;
        for( int i = 0 ; i < N; i++)
        
            cin >> a[i];
        
        
        for( int i = N - M; i < N; i++)
        
            cout << a[i];
            cnt++;
            if(cnt < N )
                cout << " ";
        
        
        for( int i = 0; i < N - M; i++)
        
            cout << a[i];
            cnt ++;
            if(cnt < N )
                cout << " ";
        
        
        return 0;
    
    

【PAT B1012】数字分类