【第六章】 数学问题

 

(6.1)节 水平称重

1、题干:

 

2、解答思路:将输入的数转化为3进制,由于不能出现两个以上一样的砝码,所以砝码只能出现一次,3进制表示的数表示砝码,符号表示不同盘

3、关键代码

string  there(int a,int b)//将a转化成b进制,b<10;返回string对象

{

string str,t;

int q;

while(a>=b)

{

       q=a%b;

       a=a/b;

       str+=q+48;

}

str+=a+48;

//for(int i=str.size()-1;i>=0;i--)

//    t+=str[i];//没有这个语句得到的是反的字符串

return str;

}

void text(string a)//针对3进制 ,取there的返回值为参数

{int b=3;

       int  t[a.size()+1];

       for(int i=0;i<a.size();i++)

       {

              if(a[i]==2+48)///3

                  {

                     t[i]=-1;

                     if(i<a.size()-1)

                            a[i+1]+=1;

                     else

                            t[i+1]=1;

                     }

              else if(a[i]==48+1) t[i]=1;

              else  t[i]=0;

             

              if(a[i]==3)///需要进位

                     {

                     t[i]=0;

                     if(i<a.size()-1)//是否最后一位

                            a[i+1]+=1;

                     else

                            t[i+1]=1;

                     }

      

       }     

              for(int i=0;i<=a.size();i++)//变成十进制砝码

       {int b=1;

                     for(int j=0;j<i;j++)

                     b*=3;

                     t[i]*=b;

}

              for(int i=a.size();i>=0;i--)//出

       {cout<<t[i];

}

        }

(6.2) Nim游戏

1、题干

 

2、解答思路:将每堆石头的数量通过异或加起来,结果为0的话,先拿的必输,

不为0的话,先拿的就赢  异或ab = (¬a b) (a ¬b) 同为0,异为1

3、关键代码:

void stopt(int a[],int n)

{int ret=0;

       for(int i=0;i<n;i++)

              ret^=a[i];

       if(ret==0)

       cout<<"先拿的输"<<endl;

       else

       cout<<"先拿的赢"<<endl;

}

(6.3)节 Nim问题博弈

1、题干:

 

2、解答思路:题目要求输入棋子的位置,棋子不断向前移动,最后不能移动的就输

在棋子顺序排列下;

3、关键代码:

void stopt(int a[],int n)///n个棋子,a排序好的

{int ret=0;

       if(n&1==1)//奇数

              {for(int i=0;i<n;i+=2)

                     ret^=(i==0)?(a[0]-1):(a[i]-a[i-1]-1);

              }

       else //偶数

              {for(int i=1;i<n;i+=2)

                     ret^=(a[i]-a[i-1]-1);

              }

       if(ret==0)

       cout<<"先动的输"<<endl;

       else

       cout<<"先动的赢"<<endl;

}

 

(6.4)节 数学公式

1、题干:

 

 

 

(6.5)节 欧几里得算法

1、题干:

 

(6.6)节 欧几里得算法拓展-贝祖等式

1、题干:

 

2、解答思路:通过递归求的最大公约数后进行返回,最后求出线性方程的解。

3、关键代码

int x,y;//定义全局变量xy方程的特解

 int andmax(int a,int b)///ax+by=m, return ret最大公约数

 {

   if(b==0)///递归边界,a为最大公约数

   {x=1;y=0;

   return a;

   }

   int ret=andmax(b,a%b);

   //回溯过程计算xy

   int x1=x;

   x=y;

   y=x1-a/b*y;

   return ret;

 }

 ///线性方程ax+by=m

 //当m为andmax(a,b)的倍数时有解

void lenxy(int a,int b,int m)

{

    int d=andmax(a,b);

    if(m%d!=0)

     {

     cout<<"无解";

     return ;

     }

    int t=m/d;//倍数;

    x*=t;

    y*=t;

}

 

(6.7)节 欧几里得解“一步之遥”

1、题干:

 

2、解答思路:F=97,B=-127;得方程:97X+(-127)Y=1;求X与Y的和最小,且x,y大于0

3、关键代码

(6.8)节 求解同余方程

1、题干:

 

(6.9)节 青蛙的约会

1、题干:

 

2、解答思路:(x+km)%L=(y+kn)%L      x+km=L*t2 +P     y+kn=L*t1 +P;相减等于

(x-y)+k(m-n)=L(t1+t2)   得: (m-n)*k- L*T =y-x;要求求出K的最小正整数

3、关键代码

int x,y;//定义全局变量xy方程的 特解

 int andmax(int a,int b)///ax+by=m, return ret最大公约数

 {

   if(b==0)///递归边界,a为最大公约数

   {x=1;y=0;

   return a;

   }

   int ret=andmax(b,a%b);

   //回溯过程计算xy

   int x1=x;

   x=y;

   y=x1-a/b*y;     

   return ret;

 }

 ///线性方程ax+by=m

 //当m为andmax(a,b)的倍数时有解

void lenxy(int a,int b,int m)

{

    int d=andmax(a,b);

    if(m%d!=0)

     {

     cout<<"Impossible";

     return ;

     }

     else

     {

    int t=m/d;//倍数;

     x*=t;

    b/=d//最简状态下的b

    x=(x%b+b)%b;// 得出的x而根据b进行加减得出新值,该式子得出x的最小正整数

     cout<<x;

    }

}

 

(6.10)节 模的逆元

1、题干:

 

 

2、解答思路:

求(A/B)%9973=? ;已经知道n=A%9973; BX%9973=1;

X为B的模的逆元,即X与1/B之间

所以(A/B)%9973=(X)*A%9973=Xn;

3、关键代码

同上求出X;

(6.11)节 同余方程组

1、题干:

 

3、关键代码:

int x,y;//定义全局变量xy方程的 特解

 int andmax(int a,int b)///ax+by=m, return ret最大公约数

 {

   if(b==0)///递归边界,a为最大公约数

   {x=1;y=0;

   return a;

   }

 

   int ret=andmax(b,a%b);

   //回溯过程计算xy

   int x1=x;

   x=y;

   y=x1-a/b*y;     

 

   return ret;

 }

 ///线性方程ax+by=m

 //当m为andmax(a,b)的倍数时有解

int minx(int m[],int b[],int lenth)//m为模,b表示余数,m表示数组的个数

{

    if(lenth==0&&b[0]==0)

    return m[0];

for(int i=1;i<lenth;i++) //前两个式整合成一个新式,与后面不断循环整合,最后成一个

{

    int b2_b1=b[i+1]-b[i];

int d=andmax(m[i-1],-m[i]);

int max=m[i]*m[i-1]/d;//求最大公倍数

 //现在x的值为前面的y1  m[i-1] *y1+b[i-1]=X

 int x0=m[i-1]*x+b[i-1];///x0表示这道式子的最终结果X

 x0=(x0%max+max)%max;//X最小正整数

m[i]=x0;

b[i]=max;

//到最后数组a和数组b最后的值存着

}

return m[lenth-1]%b[lenth-1];

}

(6.12)节 素数即质数

1、题干:

 

2、关键代码:

int ss(int a)

{for(int i=2;i*i<=a;i++)

    if(a%i==0)

       return i;

    return 0;//找不到返回0

}

(6.13)节 素数即质数的筛法

1、题干:求第n个素数

2、解答思路:主要要知道要多大的空间,当数组处理不了那么大的数组时候,可以用string字符串

3、关键代码

#include<iostream>

#include<math.h>

using namespace std;

int ss(int N)

{long n=2;

while(n/log(n)<N) //log是以e为底的

       n++;//得出n大小的空间

       cout<<n<<endl;

string a;//迫于无奈,使用数组不行

for(int i=0;i<n;i++)

       {a+=48;//初始化为0  

}

int x=2;

while(x<n)

{

       if(a[x]!=48)

       {

              x++;

              continue;

       }

      

       int k=2;

       while(x*k<n)

       {a[x*k]=49;

       k++;

       }

       x++;

}     

int sum=0;

for(int i=2;i<n;i++)

{      if(a[i]==48)

              sum++;

       if(sum==N)

        return i;           

}

return 0;       

}

(6.14)节 快速幂运算

1、题干:求a的n次方

1、循环n次将a个n相乘

int k1(int a,int n)

{int ret=1;

    for(int i=0;i<n;i++)

           ret*=a;

 return ret;      

}

 

 2、通过将a=a*a,平方平方的相乘,当下一个平方大于n时,用n-当前平方的个数进行递归,最后返回递归结果。

    int k2(int a,int n)

{int ret=1;

int count=1;

int temp=a;

if(n==1)

    return a;

while((count<<1)<n)

    {

       temp*=temp;

       count<<=1;

    }

ret*=k2(a,n-count);

return ret*temp;

}

   3、将n变成2进制,当位上为1时结果才乘上;

int k3(int a,int n)

{int ret=1;

while(n!=0)

{

if((n&1)==1)

        ret*=a;

a=a*a;

n>>=1;

}

 return ret;      

}

猜你喜欢

转载自www.cnblogs.com/niliuxiaocheng/p/11983481.html