• 一次线性同余式解决问题


    问题描述;

      给出两个桶的容量(单位L),以及需要取出的水的数量(单位L),输出两个杯子倒满水的次数以及倒水的过程。

    思路:

      首先利用定理1判断是否有解,然后根据线性同余式求出两个杯子装满水的次数,然后循环模拟。

    接下来首先给出线性同余式的定义以及一些定理和推论

    1 /*
    2 定义1 如果a,b都是整数,m是正整数,则当a≢0(modm)时,称ax≡b(mod m)为模m的线性同余式。
    3 */
    4 /*
    5 定理1 设a, b是整数,m是正整数,且(a,m)=d。
    6 若d∤b,则模m的线性同余式ax≡b(mod m)无解;
    7 若d|b,则模m的线性同余式ax≡b(mod m)恰有d个模m不同余的解。 
    8 */
    1 /*
    2 推论1 若整数a与正整数m相对互素,且b是整数,则线性同余式ax≡b(mod m)有模m唯一解。
    3 */

    PS:线性同余式的证明放在文末,有兴趣的同学可以看一下。接下来开始解析:

    首先我们要检验一下用户的数据输入是否有问题:

    /*
    用户输入的数据一共需要三个,分别是桶的容量a和b,还有我们最终需要取出的容量c,如果需要我们取出的水的数量比大的那个桶的容量还要的大话,那么我们判断用户的输入是错误的。
    */
    void panduan(int &a,int &b,int &c){
        if(a<b){
            int m=a;
            a=b;
            b=m;
        }
        if(a<c){
            cout<<"输入错误"<<endl;
            exit(0);
        }
    }

    接下来我们要运用线性同余式来解决问题,顺便求出解x,y

    /*
    同上,a,b,c意思不变,x代表a桶需要几桶,y代表b桶需要几桶。
    函数的返回值是a和b的最大公约数。
    这里我们运用的是递归的思想,在寻求a,b最大公约数的过程中逐步求出x,y的大小
    */
    int Extended_GCD(int a,int b,int &x,int &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return a;
        }
     
        int temp;
        int gcd=Extended_GCD(b,a%b,x,y);
        temp=x;
        x=y;
        y=temp-a/b*y;
        return gcd;
    }

    接下来我们开始模拟输出

    /*
    首先我们注意,我们在这段程序中调用了Extended_GCD函数,这里的返回值gcd就是a和b的最大公约数,然后我们运用定理一来判断答案是否存在。
    如果存在的话我们就能算出解x,y。
    一般情况下,x和y是一正一负的,我们需要先判断他们两个谁是正的谁是负的,然后再开始模拟。否则就会出现你从一个空桶里倒出来水,然后再加水的笑话了
    */
    void doit(int &a,int &b,int &c,int &x,int &y){
        int gcd=Extended_GCD(a,b,x,y);
        if(c%gcd!=0){
            cout<<"无整数解"<<endl;
            return;
        }else{
            x=x*c/gcd;
            y=y*c/gcd; 
            cout<<"能拿出指定升数"<<endl; 
            cout<<"A桶容量: "<<a<<"L B桶容量: "<<b<<" L"<<endl; 
            cout<<x<<" "<<y<<endl;
        }    
        if(x>0){
            int cup_a=0,cup_b=0;
            while(x!=0||y!=0){
                if(cup_a==0&&x>0){
                    cup_a=a;
                    cout<<"-->A: "<<a<<" L"<<endl;
                    print(cup_a,cup_b);
                    x--;
                }
                if(cup_b!=b){
                    int z=min(abs(b-cup_b),cup_a);
                    cout<<"A->B: "<<z<<" L"<<endl;
                    cup_a-=z;
                    cup_b+=z;
                    print(cup_a,cup_b);
                }else{
                    y++;
                    cup_b=0;
                    cout<<"B--> "<<b<<" L"<<endl;
                    print(cup_a,cup_b);
                }
                if(cup_a==c||cup_b==c) break;
            }
        }else{
            int cup_a=0,cup_b=0;
            while(x!=0||y!=0){
                if(cup_b==0&&y>0){
                    cup_b=b;
                    cout<<"-->B: "<<b<<" L"<<endl;
                    y--;
                    print(cup_a,cup_b);
                }
                if(cup_a!=a){
                    int z=min(abs(a-cup_a),cup_b);
                    cout<<"B->A: "<<z<<" L"<<endl;
                    cup_a+=z;
                    cup_b-=z;
                    print(cup_a,cup_b);
                }
                if(cup_a==a){
                    x++;
                    cup_a=0;
                    cout<<"A-->: "<<a<<" L"<<endl;
                    print(cup_a,cup_b);
                }
                if(cup_a==c||cup_b==c) break;
            }
        }
    }

    附上总的代码

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 
      5 using namespace std;
      6 
      7 void panduan(int &a,int &b,int &c){
      8     if(a<b){
      9         int m=a;
     10         a=b;
     11         b=m;
     12     }
     13     if(a<c){
     14         cout<<"输入错误"<<endl;
     15         exit(0);
     16     }
     17 }
     18 
     19 void print(int cup_a,int cup_b){
     20     cout<<"目前情况 A:"<<cup_a<<"L B:"<<cup_b<<"L"<<endl;
     21 }
     22 
     23 int Extended_GCD(int a,int b,int &x,int &y)
     24 {
     25     if(b==0)
     26     {
     27         x=1;
     28         y=0;
     29         return a;
     30     }
     31  
     32     int temp;
     33     int gcd=Extended_GCD(b,a%b,x,y);
     34     temp=x;
     35     x=y;
     36     y=temp-a/b*y;
     37     return gcd;
     38 }
     39 
     40 void doit(int &a,int &b,int &c,int &x,int &y){
     41     int gcd=Extended_GCD(a,b,x,y);
     42     if(c%gcd!=0){
     43         cout<<"无整数解"<<endl;
     44         return;
     45     }else{
     46         x=x*c/gcd;
     47         y=y*c/gcd; 
     48         cout<<"能拿出指定升数"<<endl; 
     49         cout<<"A桶容量: "<<a<<"L B桶容量: "<<b<<" L"<<endl; 
     50         cout<<x<<" "<<y<<endl;
     51     }    
     52     if(x>0){
     53         int cup_a=0,cup_b=0;
     54         while(x!=0||y!=0){
     55             if(cup_a==0&&x>0){
     56                 cup_a=a;
     57                 cout<<"-->A: "<<a<<" L"<<endl;
     58                 print(cup_a,cup_b);
     59                 x--;
     60             }
     61             if(cup_b!=b){
     62                 int z=min(abs(b-cup_b),cup_a);
     63                 cout<<"A->B: "<<z<<" L"<<endl;
     64                 cup_a-=z;
     65                 cup_b+=z;
     66                 print(cup_a,cup_b);
     67             }else{
     68                 y++;
     69                 cup_b=0;
     70                 cout<<"B--> "<<b<<" L"<<endl;
     71                 print(cup_a,cup_b);
     72             }
     73             if(cup_a==c||cup_b==c) break;
     74         }
     75     }else{
     76         int cup_a=0,cup_b=0;
     77         while(x!=0||y!=0){
     78             if(cup_b==0&&y>0){
     79                 cup_b=b;
     80                 cout<<"-->B: "<<b<<" L"<<endl;
     81                 y--;
     82                 print(cup_a,cup_b);
     83             }
     84             if(cup_a!=a){
     85                 int z=min(abs(a-cup_a),cup_b);
     86                 cout<<"B->A: "<<z<<" L"<<endl;
     87                 cup_a+=z;
     88                 cup_b-=z;
     89                 print(cup_a,cup_b);
     90             }
     91             if(cup_a==a){
     92                 x++;
     93                 cup_a=0;
     94                 cout<<"A-->: "<<a<<" L"<<endl;
     95                 print(cup_a,cup_b);
     96             }
     97             if(cup_a==c||cup_b==c) break;
     98         }
     99     }
    100 }
    101 
    102 int main(){
    103     int a,b,c,x,y;
    104     cout<<"请输入两个桶的容量(以空格隔开)"<<endl;
    105     cin>>a;
    106     cin>>b;
    107     cout<<"请输入要取得升数"<<endl;
    108     cin>>c;
    109     
    110     panduan(a,b,c);
    111     
    112     doit(a,b,c,x,y);
    113     
    114     return 0;
    115 } 
    View Code

    以下给出线性同余式可解的证明

    /*
    首先
    线性同余式ax≡b(mod m)
    
    两变元的线性方程ax-my=b。
       因而
    整数x是线性同余式ax≡b(mod m)的解
    
    存在整数y,使得ax-my=b。
    由于线性同余式ax≡b(mod m)有解的充要条件为存在整数y使得ax-my=b,同时由(a,m)=d,得到d|a且d|m,进而由定理1.1.2知d|b。因而若d∤b,则ax≡b(mod m)无解。
    若d|b,则首先证明两变元线性方程ax-my=b有无穷多个解(x,y),从而线性同余式ax≡b(mod m)就有无穷多个解x。随后确定线性同余式ax≡b(mod m)的这无穷多个解中模m不同余的解的个数。
    假设d|b,则存在整数e使得de=b。又(a,m)=d,故由定理1.3.3知存在整数s和t使得d=as-mt。因而
    b=de=(as-mt)e=a(se)-m(te),
         因而x0=se,y0=te是方程ax-my=b的一个特解。
        其次若设x=x0+(m/d)n,y=y0+(a/d)n,n为整数,
        则由
             ax-my=a(x0+(m/d)n)-m(y0+(a/d)n)=ax0-my0=b,
          知(x0+(m/d)n, y0+(a/d)n)是方程ax-my=b的解;
    接下来将证明方程ax-my=b的每一个解都具有形式
    x=x0+(m/d)n,y=y0+(a/d)n,n为整数。
       设x与y是方程ax-my=b的解,x0=se,y0=te是方程ax-my=b的一个特解,即ax0-my0=b,则
    (ax-my)-(ax0-my0)=0,即
             a(x-x0)-m(y-y0)=0,也即
    a(x-x0)=m(y-y0),
       等式两边同除以d,得到
    (a/d)(x-x0)=(m/d)(y-y0),
      由(a,m)=d得到(a/d,m/d)=1,进而(a/d)|(y-y0),即存在整数n使得
    (a/d)n=(y-y0),也即
          y=y0+(a/d)n,
    接下来,将y的取值代入方程a(x-x0)=m(y-y0),得到
    a(x-x0)=m(a/d)n,
          即
    x=x0+(m/d)n。
          因而方程ax-my=b的每一个解都具有形式x=x0+(m/d)n,y=y0+(a/d)n,n为整数。
          由于n为任意整数,因而两变元线性方程ax-my=b有无穷多个解(x,y),从而线性同余式ax≡b(mod m)就有无穷多个解x。
    
    最后确定线性同余式ax≡b(mod m)的模m不同余的解的个数。
          首先确定两个解x1=x0+(m/d)n1与x2=x0+(m/d)n2模m不同余的条件。
    确定两个解x1=x0+(m/d)n1与x2=x0+(m/d)n2模m同余的条件。
    x0+(m/d)n1≡x0+(m/d)n2(modm),
                                             
    (m/d)n1≡(m/d)n2(modm),
           这里由(m/d)|m,有(m, m/d)=m/d,因而
     (m/d)n1≡(m/d)n2(modm) n1≡n2(mod d),
          即ax≡b(mod m)的解x1=x0+(m/d)n1与x2=x0+(m/d)n2模m同余当且仅当n1和n2模d同余。
                   因而若取x=x0+(m/d)n,并让n取遍模d的一个完全剩余系,就可以得到线性同余式ax≡b(mod m)的模m不同余的一个解集。
                  其中x=x0+(m/d)n,n=0,1,2,…,d-1就是线性同余式ax≡b(mod m)的模m不同余的一个解集。 
    
    */

      

  • 相关阅读:
    2014-11-1 NOIP模拟赛2
    洛谷P1014 Cantor表
    洛谷P1011 车站
    洛谷P1013 进制位
    2014-11-1 NOIP模拟赛1
    2017-9-20 NOIP模拟赛
    洛谷P2016 战略游戏
    洛谷P3182 [HAOI2016]放棋子
    2014-10-31 NOIP模拟赛
    洛谷P1736 创意吃鱼法
  • 原文地址:https://www.cnblogs.com/yuemo/p/9758362.html
Copyright © 2020-2023  润新知