892练习(二):中国剩余定理、n皇后问题、欧几里得算法

一、中国剩余定理

在这里插入图片描述
即孙子定理:有一个数 kmod3=2,kmod5=3,kmod7=2 则k=?

1、前提定理

定理1:两个数相加,若存在一个加数不能被a整除,则它们的加数就不能被a整除。
定理2:两个数不能整除,若除数扩大(或缩小)了几倍,而被除数不变,则它们的商和余数同时扩大(或缩小)相同的倍数(余数必小于除数)

2、计算过程

(1)求出最小公倍数
3* 5 * 7 = 105;
(2)求各个数对应的基础数
3:105/3=35;
35/3 = 11…2; // 三三数余2 基础数35

5:105/5=21;
21/5=4…1
定理2把1扩大3倍到3,那么被除数也扩大3倍,得到21*3=63;//五五数余三 基础数63

7:105/7=15
15/7=2…1
定理2把1扩大2倍到2,被除数也扩大两倍,得到15*2=30;//七七数余二 基础数30

(3)把得到的基础数相加
35+63+30=128;
为什么要相加:35可以被5,7整除,将63+30看作一个整体,可以被3整除,所以得到的结果仍满足题目要求;但不一定是最小的,这时候用到最小公倍数,最小公倍数是同时可以被三个数整除的最小的一个数,所以减去它剩余下来的数还是符合要求的。
减去最小公倍数得到满足题意的最小数 x=128-105=23;

3、算法思想总结

已知m1,m2,m3是两两互质的正整数(3,5,7),求最小正整数x,使它被m1,m2,m3除所得的余数分别是c1,c2,c3(2,3,2)

孙子算法的思想是:先分别求出被mi整除余ci,而被其他两个数整除的数Ri(i=1,2,3),我们称之为基础数。则所求的数之一便是基础数相加,即R1+R2+R3。但这个数不一定是最小的x,此时需要用到最小公倍数,若大于最小公倍数,则减去最小公倍数所得的数就是满足题目要求的x。

二、n皇后问题

在这里插入图片描述
如下图是一个6皇后问题的一个解:
在这里插入图片描述

回溯法-剪枝

1、什么是回溯法

在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点(开始结点)出发搜索解空间树

2、剪枝函数

回溯法搜索解空间时,通常采用两种策略避免无效搜索,提高回溯的搜索效率:
在这里插入图片描述
这两类函数通称为剪枝函数。

总结:回溯法=深度优先搜索+剪枝函数

3、代码

int n,cnt=0;
int a[n];//第i行的皇后放在a[i]列
void queen(int i,int n){//第i行的皇后放在什么位置 放置1~i的n皇后
	if(i>n){//所有皇后放置完毕,得到一个解
		cnt++;
	}
	for(int j=1;j<=n;j++){	
	if(check(i,j)){//(i,j)这个位置可以放皇后
		a[i]=j;//皇后放在第j列
		queen(i+1,n)//递归调用
	}
  }
}

bool check(int i,int j){//检查(i,j)这个位置是否可以放皇后
	for(int k=1;k<=i;k++){//k=1~i
		if(j==a[i]) return false;//同一列
		if(i+a[i]==i+j) return false;//在同一上对角线上
		if(i-a[i]==i-j) return false;//在同一下对角线上
	}
	return false;
}

int main(){
	cin>>n;//n皇后
	queen(1,n);
	count<<cnt;//输出n皇后问题有多少种解
}

三、欧几里得算法

1、欧几里得

在这里插入图片描述
欧几里得算法,就是辗转相除法!!用来求a 和 b 的最大公因子!
a = bq+r (理解:被除数=商*除数+余数 35/6=5…5)

2、扩展欧几里得

b站:最爱吃面皮
理解:在欧几里得算法的基础上得到a,b的最大公因子gcd(a,b) 后,还要求出ax+by=gcd(a,b)的系数x,y。用到递归的思想,找到前后两项的递推关系,如下

x1=y2;
y1=x2-[a/b]*y2;

递归出口是 x=1,y=0;
在这里插入图片描述

3、例题 The Balance

在这里插入图片描述
题目大意:用两种砝码,质量分别为m ,n,数量不限,称出重量为d的阿司匹林并要求两种砝码的数量越小越好,如果有相同解,输出x+y小的那组。其中x,y是砝码的数量。

#include <iostream>  
#include <algorithm>  
#include <string>  
//#include <map>  
#include <queue>  
#include <vector>  
#include <cstdio>  
#include <cstdlib>  
#include <cstring>  
#include <cmath>  
//#include <ctime>  
#include <ctype.h>  
using namespace std;  
#define LL long long  
#define inf 0x3fffffff  
  
LL gcd (LL a, LL b) //欧几里得算法
{  
    return b ? gcd (b, a%b) : a;  
}  
  
void Egcd (LL a, LL b, LL &x, LL &y)  //扩展欧几里得算法
{  
    if (b == 0)  
    {  
        x = 1, y = 0;  
        return ;  
    }  
    Egcd (b, a%b, x, y);  //递归调用
    LL tp = x;  
    x = y;  //赋值
    y = tp - a/b*y;  
}  
  
int main()  
{  
    LL xx, yy, a, b, x, y, L, n, M, N, d;  
    while (~scanf ("%lld%lld%lld%lld%lld", &xx, &yy, &M, &N, &L))  
    {  //输入
        a = L;  
        b = N - M;  
        n = xx - yy;  
        d = gcd (a, b);  
        if (n % d != 0)  
        {  
            puts ("Impossible");  
            continue;  
        }  
        a /= d;  
        b /= d;  
        n /= d;  
        Egcd (a, b, x, y);  
        y *= n;  
        if (a < 0) a = -a;    //周期是正的  
        y = (y % a + a) % a;  
        printf ("%lld\n", y);  
    }  
    return 0;  
}  

另一种主函数中的代码…
在这里插入图片描述
这两个都有点看不懂…求讲解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值