(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的话,先拿的就赢 异或a⊕b = (¬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;
}