[Coursera 计算导论与C语言基础] 抄写作业

抄写题#1:实现冒泡排序

来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

请根据自己的理解编写冒泡排序算法,数组大小1000以内

输入

第一行是n,表示数组的大小

接着n行是数组的n个元素

输出

排序之后的结果

一个元素一行

请完全按照如下的程序书写代码,并在书写的过程中体会优秀的代码风格:

    #include <iostream>
    using namespace std;

    int main() {
        int n, a[1000]; // 一共n个数,n不超过1000。a用来保存这些数
        cin >> n;  
        // 输入n个数  
        for (int i = 0; i < n; i++) {
          cin >> a[i];
    }  
    // 冒泡,不断比较相邻的两个数,如果顺序错了,那么就交换
    for (int i = 0; i < n - 1; i++) {
      for (int j = 1; j < n - i; j++) {      
        if (a[j - 1] > a[j]) {
          int temp = a[j];
          a[j] = a[j - 1];
          a[j - 1] = temp;
        }    
      }  
    }  
    // 依次输出
   for (int i = 0; i < n; i++) {
     cout << a[i] << endl;  
   }  
   return 0;
}

抄写题#2:奇偶排序(一)

来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

输入十个整数,将十个整数按升序排列输出,并且奇数在前,偶数在后。

输入

输入十个整数

输出

按照奇偶排序好的十个整数

请完全按照如下的程序书写代码,并在书写的过程中体会优秀的代码风格:

 #include <iostream>
    using namespace std;
    
    int main() {
      int a[10];
      for (int i = 0; i < 10; i++) {
        cin >> a[i];
      }
      // 首先,我们把奇数放到数组左边,偶数放到数组右边
      int l = 0, r = 9; //用左手和右手分别指向数组两端
      while (l <= r) {
        bool leftIsOdd = a[l] % 2 == 1;
        bool rightIsEven = a[r] % 2 == 0;
        if (leftIsOdd) {
          l++;
        } else if (rightIsEven) {
          r--;
        } else if (!leftIsOdd && !rightIsEven) {
          int temp = a[l];
          a[l] = a[r];
          a[r] = temp;
        }
      }
      // 对l左边(奇数部分)冒泡,不断比较相邻的两个数,如果顺序错了,那么就交换
      int start = 0, end = l;
      for (int i = start; i < end - 1; i++) {
        for (int j = start + 1; j < start + end - i; j++) {
          if (a[j - 1] > a[j]) {
            int temp = a[j];
            a[j] = a[j - 1];
            a[j - 1] = temp;
          }
        }
      }
      // 对l右边(偶数部分)冒泡,不断比较相邻的两个数,如果顺序错了,那么就交换
      start = l, end = 10;
      for (int i = start; i < end - 1; i++) {
        for (int j = start + 1; j < start + end - i; j++) {
          if (a[j - 1] > a[j]) {
            int temp = a[j];
            a[j] = a[j - 1];
            a[j - 1] = temp;
          }
        }
      }
      for (int i = 0; i < 10; i++) {
        cout << a[i] << ' ';
      }
      return 0;
    }

抄写题#3:奇偶排序(二)

来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

和上题一样,但是要求用第二种解法

输入

输入十个整数

输出

按照奇偶排序好的十个整数

请完全按照如下的程序书写代码,并在书写的过程中体会优秀的代码风格:

    #include <iostream>
    using namespace std;
    
    int main() {
      int a[10];
      for (int i = 0; i < 10; i++) {
        cin >> a[i];
      }  
      // 冒泡,不断比较相邻的两个数,如果顺序错了,那么就交换
      for (int i = 0; i < 9; i++) {
        for (int j = 1; j < 10 - i; j++) {      
      // 与刚才的冒泡排序不同,我们不只是通过较数字的大小决定顺序
      // 如果左边的为偶数,右边的为奇数,那么顺序也需要颠倒
      bool leftIsEven = a[j - 1] % 2 == 0;
      bool rightIsEven = a[j] % 2 == 0;
      if ((leftIsEven && !rightIsEven) ||
          (leftIsEven == rightIsEven && a[j - 1] > a[j])) {        
        int temp = a[j];        
        a[j] = a[j - 1];
        a[j - 1] = temp;
      }
    }
  }  
  for (int i = 0; i < 10; i++) {
    cout << a[i] << ' ';
  }  
  return 0;
}

抄写题#4: 晶晶赴约会

来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

晶晶的朋友贝贝约晶晶下周一起去看展览,但晶晶每周的1、3、5有课必须上课,请帮晶晶判断她能否接受贝贝的邀请,如果能输出YES;如果不能则输出NO。

输入

输入有一行,贝贝邀请晶晶去看展览的日期,用数字1到7表示从星期一到星期日。

输出

输出有一行,如果晶晶可以接受贝贝的邀请,输出YES,否则,输出NO。注意YES和NO都是大写字母!

#include <iostream>
using namespace std;
int main() {
    int a;
    cin >> a;
    if (a == 1 || a == 3 || a == 5)
        cout << "NO" << endl;
    else
        cout << "YES" << endl;
    return 0;
}

抄写题#5:奇数求和

来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

计算正整数 m 到 n(包括m 和 n )之间的所有奇数的和,其中,m 不大于 n,且n 不大于300。例如 m=3, n=12, 其和则为:3+5+7+9+11=35

输入

两个数 m 和 n,两个数以空格间隔,其中 0<=m <= n <= 300 。

输出

奇数之和

#include <iostream>
using namespace std;
int main() {
    int m, n, result = 0;
    cin >> m >> n;
    while (m <= n) {
        //对于m和n之间的每一个数, 如果它是奇数,那么就加入到我们的结果里。如果不是就跳过。
        if (m % 2 == 1)
            result += m;
        m++;
    }
    //最后输出
    cout << result << endl;
    return 0;
}

抄写题#6:整数的个数

来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

给定k(1<k<100)个正整数,其中每个数都是大于等于1,小于等于10的数。写程序计算给定的k个正整数中,1,5和10出现的次数。

输入

输入有两行:第一行包含一个正整数k,第二行包含k个正整数,每两个正整数用一个空格分开。

输出

输出有三行,第一行为1出现的次数,,第二行为5出现的次数,第三行为10出现的次数。

#include <iostream>
using namespace std;
int main(){
    int k;
    cin>>k;
    int n1=0, n5=0, n10=0;
    for (int i=0;i<k;i++){
        int n;
        cin>>n;
        if (n == 1) n1++;
        else if (n == 5) n5++;
        else if (n == 10) n10++;
    }
    cout<<n1<<endl;
    cout<<n5<<endl;
    cout<<n10<<endl;
    return 0;
}

抄写题#7:1的个数

来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

给定一个十进制整数N,求其对应2进制数中1的个数

输入

第一个整数表示有N组测试数据,其后N行是对应的测试数据,每行为一个整数。

输出

N行,每行输出对应一个输入。

# include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        int x, ans = 0;
        cin >> x;
        while (x > 0) {
            ans += x % 2;
            x /= 2;
        }
        cout << ans << endl;
    }
    return 0;
}

抄写题#8:数组逆序重放

来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

将一个数组中的值按逆序重新存放。例如,原来的顺序为8,6,5,4,1。要求改为1,4,5,6,8。

输入

输入为两行:第一行数组中元素的个数n(1<n<100),第二行是n个整数,每两个整数之间用空格分隔。

输出

输出为一行:输出逆序后数组的整数,每两个整数之间用空格分隔。

#include <iostream>
using namespace std;
int a[100];
int main() {
    int n;
    cin >> n;
    for (int i = 0; i<n; i++)
        cin >> a[i];
    while (n--) { //常用的倒序计数循环,等价于while(n-->0)
        cout << a[n];
        if (n > 0) cout << " "; //如果不是最后一个数那么就要用空格分隔开
    }
    return 0;
}
//顺序输入倒序输出,但是如果我们要求通过修改数组本身实现逆序重放应该怎么做呢?

抄写题#9:细菌实验分组

来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

有一种细菌分为A、B两个亚种,它们的外在特征几乎完全相同,仅仅在繁殖能力上有显著差别,A亚种繁殖能力非常强,B亚种的繁殖能力很弱。在一次为时一个小时的细菌繁殖实验中,实验员由于疏忽把细菌培养皿搞乱了,请你编写一个程序,根据实验结果,把两个亚种的培养皿重新分成两组。

细菌繁殖能力(繁殖率)的量化标准为一个小时内细菌数量增长的比例(繁殖率 = 一小时后细菌数量 / 原本细菌数量)。

两个亚种繁殖能力差异很大,这意味着对于任意两个同种细菌培养皿的繁殖率的测量值之间的差异要小于任意两个异种细菌培养皿繁殖率的测量值之间的差异。即:

输入

输入有多行,第一行为整数n(n≤100),表示有n个培养皿。

其余n行,每行有三个整数,分别代表培养皿编号,试验前细菌数量,试验后细菌数量。假设试验没有误差。

输出

输出有多行:

第一行输出A亚种培养皿的数量,其后每行输出A亚种培养皿的编号,按繁殖率升序排列。

然后一行输出B亚种培养皿的数量,其后每行输出B亚种培养皿的编号,也按繁殖率升序排列。

#include <iostream>
using namespace std;
int main() {
  int n; // n为细菌的数量
  // id记录细菌的编号, rate记录细菌的繁殖率,第i个细菌对应id[i]和rate[i]
  int id[100];
  double rate[100];

  cin >> n;
  for (int i = 0; i < n; i++) {
    int initial, final;
    cin >> id[i] >> initial >> final;
    rate[i] = (double)final / initial;
  }  

// 对整个细菌排序
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n - i - 1; j++) {
      if (rate[j + 1] > rate[j]) {
        int tmpId = id[j];
        id[j] = id[j + 1];
        id[j + 1] = tmpId;
        double tmpRate = rate[j];
        rate[j] = rate[j + 1];
        rate[j + 1] = tmpRate;
      }
    }
  }  

// 记录最大的差
  double maxDiff = 0;
  // 和最大差的下标
  int maxDiffIndex = 0;
  for (int i = 0; i < n - 1; i++) {
    double diff = rate[i] - rate[i + 1];
    if (maxDiff < diff) {
      maxDiff = diff;
      maxDiffIndex = i;
    }  
  }
  
  //输出繁殖率较大的那组细菌
  cout << maxDiffIndex + 1 << endl;
  for (int i = maxDiffIndex; i >= 0; i--) {
    cout << id[i] << endl;
  }

  //输出繁殖率较小的那组细菌
  cout << n - maxDiffIndex - 1 << endl;
  for (int i = n - 1; i >= maxDiffIndex + 1; i--) {
    cout << id[i] << endl;
  }
  return 0;
}

抄写题#10: 约瑟夫问题

来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)

总时间限制: 1000ms 内存限制: 65536kB

描述

约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。

输入

每行是用空格分开的两个整数,第一个是 n, 第二个是 m ( 0 < m,n <=300)。最后一行是:

0 0

输出

对于每行输入数据(最后一行除外),输出数据也是一行,即最后猴王的编号


#include<iostream>
using namespace std;

//一共最多有300只猴子
int succedent[300]; //这个数组用于保存一个猴子后一位是谁,
      //比如“next[5]的值是7”就是说5号猴子的下一位是7号猴子,6号猴子已经在之前退出了。
int precedent[300];//这个数组用于保存一个猴子前一位是谁,用法和上面的类似。

int main() {
  int n, m;
  while (true) {
    cin >> n >> m;
    if (n == 0 && m == 0)
      break;
    for (int i = 0; i < n - 1; i++) {
      succedent[i] = i + 1;
      precedent[i + 1] = i;
    }
    succedent[n - 1] = 0;
    precedent[0] = n - 1;

    int current = 0;
    while (true) {
      //如果一共要报m次号,那么取m-1次succedent之后就是需要退出的那只猴子
      for (int count = 0; count < m-1; count++)
        current = succedent[current];

      int pre = precedent[current];
      int suc = succedent[current];
      //让current号猴子退出很简单,就是把前一位的“下一位”指向current的下一位,
      //下一位的“前一位”指向current的前一位就好了
      succedent[pre] = suc;
      precedent[suc] = pre;
      if (pre == suc) {
        //如果只剩下两个了,那么每个人的前位和后位就是同一个了。
        //current是退出的,那么另一个就是剩下的。
        //我们的序号是从0编号的,输出时要加一
        cout << pre+1 << endl;
        break;
      }
      current = suc;
    }
  }
  return 0;
}

抄写题#11:分数求和

来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

输入n个分数并对他们求和,用约分之后的最简形式表示。

比如:

q/p = x1/y1 + x2/y2 +....+ xn/yn,

q/p要求是归约之后的形式。

如:5/6已经是最简形式,3/6需要规约为1/2, 3/1需要规约成3,10/3就是最简形式。

PS:分子和分母都没有为0的情况,也没有出现负数的情况

输入

第一行的输入n,代表一共有几个分数需要求和

接下来的n行是分数

输出

输出只有一行,即归约后的结果

#include<iostream>
using namespace std;

int main() {
  int n;
  cin >> n;
  int sumn = 0, sumd = 1;//储存结果,sumn/sumd
  while (n--) {
    int num, deno;
    char slash;//专门用来吃掉/的
    cin >> num >> slash >> deno;
    //先相加 a/b + c/d = (a*d+c*b)/(b*d)
    sumn = sumn*deno + num*sumd;
    sumd = sumd*deno;
  }
  //后约分
  //先求最大公约数gcd,这里用的是欧几里得法
  int a = sumd, b = sumn, c;
  while (a != 0) {
    c = a; a = b%a; b = c;
  }
  int gcd = b;
  //分子分母同时除以gcd就可以完成约分
  sumd /= gcd;
  sumn /= gcd;
  if (sumd > 1)
    cout << sumn << '/' << sumd << endl;
  else
    cout << sumn << endl;
  return 0;
}
//我们计算过程中结果分母是不断乘以新输入的分母,最后约分的。这样可能导致这个过程中分母过大溢出。
//这道题的数据比较简单,并没有出现那种情况。但大家可以思考一下,如果出现了那种情况怎么办呢?(不要用大整数啊)
/*我给大家一组测试数据,看看你修改过的程序能不能通过这组数据吧:
样例输入:
2
1/100000000
1/100000000
样例输出:
1/50000000
*/

抄写题#12:点评赛车

来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

4名专家对4款赛车进行评论

1)A说:2号赛车是最好的;

2)B说:4号赛车是最好的;

3)C说:3号赛车不是最好的;

4)D说: B说错了。

事实上只有1款赛车最佳,且只有1名专家说对了,其他3人都说错了。

请编程输出最佳车的车号,以及说对的专家。

输入

无输入。

输出

输出两行。第一行输出最佳车的车号(1-4中的某个数字)。第二行输出说对的专家(A-D中的某个字母)。

#include<iostream>
using namespace std;
int main(){
    // 很多同学在论坛中问,autograder是怎么工作的。
    // 答案就是:autograder只看在所有测试用例上的输出是否正确。
    // 由于本题没有输入,输出也唯一,
    // 所以,如果我们知道了答案(例如人工地一一枚举过来)那我们就可以直接输出啦!结果如下:
//       cout << "3" << endl << "D" << endl;
    // oj系统的autograder可辨识不了我们的程序使用的算法是否符合要求
    //(事实上,任何关于程序的非平凡性质都是不可判定的!
    //  ————等等,那autograder怎么工作呢?
    //  ————原来,autograder限制了程序运行的时间。其目的当然包括要求我们使用的算法不能太笨拙。
    //            更重要的是,如果我们允许最笨拙的方法并且对时间不作任何限制,
    //            那么autograder就不能正确判定所有的程序啦。)
    // 不过呢,这么输出是对autograder的一种错误使用方式,因为显然这不是本道题的考察内容。
    // 所以,我们还是老老实实地用“程序”来解这个问题的答案。
    
    // 用best枚举最好的车
    int best;    
    for(best = 1; best <= 4; best++){
        // a b c d记录四位专家的话
        bool a = (best == 2);
        bool b = (best == 4);
        bool c = !(best == 3);
        bool d = !b;                
        if (a + b + c + d != 1)
            continue; // 不符合只有1位专家说对的条件
                // 输出最佳的车
        cout << best << endl;
        // 输出判断正确的专家
        if ( a == 1)
            cout << "A" << endl;
        else if ( b == 1)
            cout << "B" << endl;
        else  if ( c == 1)
            cout << "C" << endl;
        else
            cout << "D" << endl;
    }        
    return 0;
}





猜你喜欢

转载自blog.csdn.net/qq_30945147/article/details/80633224