第五周作业的抄写部分

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

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

0 0

输出
对于每行输入数据(最后一行除外),输出数据也是一行,即最后猴王的编号
样例输入
6 2
12 4
8 3
0 0
样例输出
5
1
7
*/
#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是退出的,那么另一个就是剩下的
                cout << pre+1 << endl;
                break;
            }
            current=suc;
        }
    }
    return 0;
}
/*
描述
输入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行是分数
输出
输出只有一行,即归约后的结果
样例输入
2
1/2
1/3
样例输出
5/6
*/
#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;
}
//如下为以上分数求和的改进,即使约分防止分母过大而溢出
#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;
    //对计算后的分数化简,每次都化简避免分母过大而溢出
        int a=sumd,b=sumn,c;
        while(a!=0)
        {
            c=a;a=b%a;b=c;
        }
        int gcd =b;
        //分子分母同时除以gcd就可以完成约分
        sumd /=gcd;
        sumn /=gcd;
    }
    //后约分
    //先求最大公约数gcd,这里用的是欧几里得法

    if(sumd>1)
    {
        cout << sumn << '/' << sumd << endl;
    }
    else
        cout << sumn << endl;
    return 0;
}
//不会的是欧几里得法求最大公约数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值