算法设计与分析基础学习笔记--第一章



第一章
欧几里德算法又称辗转相除法,用于计算两个整数a, b的最大公约数。
基本算法:设a=qb+r,其中a,b,q,r都是整数,则gcd(a,b)=gcd(b,r),即gcd(a,b)=gcd(b,a%b)
证明:
(1)假设d是a,b的一个公约数,a可以表示成a = kb + r,则r = a % b,
则有d|a, d|b, 而r = a - kb,故 d|r,
因此d是(b,a mod b)的公约数;
(2)假设d 是(b,a mod b)的公约数,
则 d | b , d | r ,而 a = kb +r
因此, d也是(a,b)的公约数
因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证

计算gcd(m, n)的欧几里得算法:
(1)如果n=0,返回m的值作为结果, 同时过程结束; 否则, 进入第二步.
(2)取m%n的余数, 将余数赋给r;
(3)将n的值赋给m, 将r的值赋给n, 返回第一步。

分析:
通过观察,我们发现,每经过一次循环,参加运算的两个算子中的后一个都会变得更小,而且绝对不会变成负数。
#include
using namespace std;

unsigned int euclid(unsigned int m, unsigned int n)
{
        unsigned int r = 0;
        while (0 != n)
        {
                r = m % n;
                m = n;
                n = r;
        }
        return m;
}

int main()
{
        cout << euclid(12, 60) << endl;
        return 0;
}


扩展欧几里德算法
对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,
必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。
(1)当b=0时, 有gcd(a,b)=a, 此时x=1, y=0
(2)当b不为0时, 根据欧几里得定理gcd(a,b)=gcd(b,a%b)
可得ax+by=gcd(a,b)
gcd(b,a%b)=bx′+(a%b)y′,即
ax+by=bx′+(a%b)y′=bx′+(a−b*[a/b])y′

移项得
ax+by=bx′+(a%b)y′=ay′+b(x′−[a/b]y′)

根据恒等定理,有
x=y′
y=x′−[a/b]y′

注释:[a/b]代表取小于a/b的最大整数

补充:关于使用扩展欧几里德算法解决不定方程的办法
  对于不定整数方程pa+qb=c, 若 c % gcd(p, q)=0,则该方程存在整数解,否则不存在整数解。
  上面已经列出找一个整数解的方法,在找到p * a+q * b = gcd(p, q)的一组解p0,q0后,p * a+q * b = gcd(p, q)的其他整数解满足:
  p = p0 + b/gcd(p, q) * t
  q = q0 - a/gcd(p, q) * t(其中t为任意整数)
  至于pa+qb=c的整数解,只需将p * a+q * b = gcd(p, q)的每个解乘上 c/gcd(p, q) 即可。
 
http://poj.org/problem?id=1061 
由题意可得:
x+mt≡y+nt(modL)
-->
(m−n)t≡y−x(modL)
-->
(m−n)t+Lk=y−x

然后,用exeuclid求

(m−n)t+Lk=gcd(m−n,L)

设r=gcd(m-n,L),c=y-x。

若c%r!=0,则无解。

这样解出t0后,最终答案就是:

(t0*c/r)%(L/r)

关于这个结论的证明:
ax1+by1=c
而我们已经解得
ax+by=gcd(a,b)=d
此时将第二个方程左右同时乘c/d,则可得:
ax*c/d+by*c/d=c
所以:  x1=x0*c/d

这样并没有完,因为这只是一组解,我们要求最小正整数解。

我们知道:若一组 < x,y > 是ax+by=c的一组解,那么

也是原方程的一组解。

这样我们只需要让解得的x不断减b/d,直到再减就为负数时,所得的x就是我们要的解。
其实这个过程就是模运算,所以最小正整数解就是:

x1=(x0*c/d)mod b/d


#include
#include
using namespace std;

long long exeuclid(long long a, long long b, long long &x, long long &y)
{
        if (0 == b)
        {
                x = 1;
                y = 0;
                return a;
        }

        long long r = exeuclid(b, a%b, x, y);

        long long tmp = x;
        x = y;
        y = tmp - (a/b) * y;

        return r;
}

int main()
{
        long long x, y, m, n, L, r, t1, t2, x0, y0, res;
        cin >> x >> y >> m >> n >> L;
        t1 = m > n ? (m - n) : (n - m);
        if (m < n)
        {
                res = x;
                x = y;
                y = res;
        }
        t2 = y > x ? (y - x) : (x - y);
        r = exeuclid(t1, L, x0, y0);
        if (t2%r != 0 )
                cout << "Impossible" << endl;
        else
        {
                t1 = L/r;
                res = ((x0*(y-x)/r)%t1+t1)%t1;
                cout << abs(res) << endl;
        }

        return 0;
}

 

你可能感兴趣的:(算法,c++编程基础)