一次线性同余式解决问题

问题描述;

  给出两个桶的容量(单位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不同余的一个解集。 

*/

 

  

posted @ 2018-10-09 08:51  月沫  阅读(600)  评论(0编辑  收藏  举报