1.9 while循环

1.9 while循环

while知识点

循环:如果条件为真,就一直执行,直到条件不为真

bool flag = true; //true, false, 1, 0
while(flag){
    //循环体
}
//解释:如果满足flag为真,就执行循环体,直到flag不为真,退出

1. 输入 n, 输出 1~n

【题目描述】输入 n, 输出 1~n(1 2 3 4 5...n)。

#include<iostream>
using namespace std;
int main(){
    int n, i=1; cin>>n;
    while(i<=n){
        cout<<i<<" ";
        i++;
    }
    return 0;
}

2. 平均分

【题目描述】考试结束后,老师想计算全体学生的平均分,你能帮助老师吗?
现在无法知道参考人数,但是知道参加考试的人都不是 0 分。
所以,提供给你的若干个考试成绩,以 0 作为计算的结束标志。

输入样例:90 0
输出样例:90

输入样例:90 89 90 0
输出样例:89.6667

#include <iostream>
using namespace std;
int main() {
    double score, sum=0, cnt=0;  cin>>score;
    while(score!=0) {
        sum += score ;
        cnt++;
        cin>>score;
    }
    cout<<sum/cnt<<endl;
    return 0;
}

3. 质数判断

【题目描述】判断给定的正整数 n(保证在 int 范围内)是否为质数,
如果 n 是质数,输出 yes; 否则,输出 no。
素数判定:如果 n(n>1) 能被 [2,n-1] 中某个整数整除,则证明n是合数,不是质数(素数)。

数学小知识:
0 是整数,但不是正整数;
1 既不是质数,也不是合数。
合数是指:大于 1, 且因子除了 1 和本身外,还有其余因子的数。

#include<cstdio>
int main() {
    int i=2, n; scanf("%d", &n);
    bool flag=1;            // 假设 n是质数
    for(int i=2; i<n; i++){ // i的取值范围 [2, n-1]
        if(n%i==0){         // 证明是合数
            flag=0; break;
        }
    }
    if(flag==0) printf("no");
    else if(n>=2) printf("yes");
    return 0;
}
//-------------------------------------
#include<cstdio>
int main() {
    int i=2, n; scanf("%d", &n);
    bool flag=1;    // 假设 n是质数
    while(i<n) {    // i的取值范围 [2, n-1]
        if(n%i==0) {// 证明是合数
            flag=0;
        }
        i++;
    }
    if(flag==0) printf("no");
    else if(n>=2) printf("yes");
    return 0;
}

4. 输入一个正整数,输出其位数

【题目描述】输入一个正整数,输出其位数
输入样例:123
输出样例:3

#include<iostream>
using namespace std;
int main(){
    int n, ans=1;//这个数至少是一位数
    cin>>n;
    while(n>9){
        n /= 10;//去掉个位数
        ans++;
    }
    cout<<ans;
    return 0;
}

5. 输入任意两个自然数,求他们的最大公约数

#include<iostream>
#include<algorithm>
using namespace std;

int main() {
    int a,b; cin>>a>>b;
    for(int i=min(a,b); i>=1; i--) {
        if(a%i==0 && b%i==0) {
            cout<<i; break;
        }
    }
    return 0;
}

6. P1150 Peter的烟

【题目描述】Peter 有 n 根烟,他每吸完一根烟就把烟蒂保存起来,k(k>1)个烟蒂可以换一个新的烟,那么 Peter 最终能吸到多少根烟呢?吸烟有害健康。

输入格式:每组测试数据一行包括两个整数 n, k (1<n,k≤1e8)
输出格式:对于每组测试数据,输出一行包括一个整数表示最终烟的根数。

输入样例:4 3
输出样例:5

输入样例:10 3
输出样例:14

解析:由于烟蒂可以换新烟,所以我们的退出条件就是剩余烟蒂不足以换得一支新烟。

举例:n=10, k=3 的时候
当前一次吸烟数量:10 ,剩余烟蒂数量为:10
可换得 3 支烟,并剩余 1 支烟蒂,故而第二次可吸烟数量:3, 剩余烟蒂数量为:4
可换得 1 支烟, 故而第三次可吸烟数量:1,剩余烟蒂数量为:2
所以三次吸烟的总数为:10+3+1=14

10/3=3...1
     4/3=1...1
         2/3=0...2
#include<iostream>
using namespace std;

int main(){
    int n,k; cin>>n>>k;
    int all = n;// 吸烟数量
    int now = n;// 现有烟蒂
    while(now>=k){
        all += now/k; // 吸烟总数 += 现有烟蒂可换新烟数量(now/k)
        now = now/k +now%k;// 现有烟蒂 = 新换的烟的数量 + 不足以换一支烟的烟蒂数量
    }
    cout<<all;
    return 0;
}

int main_2(){
    int n,k; cin>>n>>k;
    cout<<n+(n-1)/(k-1);//奥数题,解析见下
    return 0;
}

image

注明:上述奥数解法来源洛谷,总之不是我写的,而且...我觉得这个思路一般...不会想到。

补充知识:最大公约数&最小公倍数

求最大公约数的三种方法:

1.最小递减法

先找a,b的最小值,判断该值能否同时被a,b整除,如果可以该数就是答案,否则每次-1,继续判断,直到找到答案。
两个数的最大公约数最小为 1。

#include<iostream>
using namespace std;
int main() {
    int a,b;  cin>>a>>b;
    for(int i=min(a,b); i>=1; i--) {
        if(a%i==0 && b%i==0) {// 满足 i 同时是 a,b 的约数的情况
            cout<<i; break;   //因为是从大到下枚举的,所以找到的第一个数就是最大公约数
        }
    }
    return 0;
}

2.更相减损法

a-b=c,则 a,b 的最大公约数就是 b,c 的最大公约数,如果 c=0(即a=b),a 就是答案。

#include<iostream>
using namespace std;
int main() {
    int a,b;
    cin>>a>>b;

    while(a!=b) {
        //更相减损术需要考虑到两个数的大小,所以多了交换的步骤
       if(a<b){ int t=a; a=b; b= t; }
       int c = a-b;
       a = b;
       b = c;
    }
    cout<<a;
    return 0;
}

3.辗转相除法

a/b=q...r,则 a,b 的最大公约数就是 b,r 的最大公约数,如果 r=0, 则 b 就是答案(或者说如果 b=0,则 a 就是答案)。

#include<iostream>
using namespace std;
int main() {
    int a,b;
    cin>>a>>b;
    while(b!=0) {
        int r = a%b;
        a = b;
        b = r;
    }
    cout<<a;
    return 0;
}

求最小公倍数的两种方法:

1.最大递增法

原理:两个数的最小公倍数一定大于等于这两个数的最大值

先找a,b的最大值,判断该值能否同时整除a,b,如果可以该数就是答案,否则每次+1,继续判断,直到找到答案。

#include<iostream>
using namespace std;
int main() {
    int a,b;  cin>>a>>b;
    for(int i=max(a,b); ; i++) {//死循环,直到找到答案才 break
        if(i%a==0 && i%b==0) {// 如果 i能同时整除 a,b,则证明 i是 a,b的公倍数
            cout<<i; break;//由于是从公倍数的最小可能答案开始枚举,所以找到的第一个答案就是最小公倍数,就可以break了
        }
    }
    return 0;
}

2.定理法

原理:两个数的乘积等于这两个数的最大公约数与最小公倍数的乘积。

#include<iostream>
using namespace std;
int main() {
    int a,b; cin>>a>>b;
    int x=a, y=b;//用定理法求最小公倍数,则原数需要记录

    while(b!=0) {//辗转相除法求最大公约数
        int r=a%b;
        a = b;
        b = r;
    }
    int max_G = a;//最大公约数
    int min_G = x*y/max_G;//最小公倍数

    cout<<"最大公约数:"<<max_G<<endl;
    cout<<"最小公倍数:"<<min_G<<endl;
    return 0;
}

具体证明过程如下:

【一些有趣的数学证明】

posted @ 2021-08-17 19:20  HelloHeBin  阅读(826)  评论(0编辑  收藏  举报