1. 程式人生 > >ACM基礎演算法複習(STL + DFS + BFS + 並查集 + 快速冪 + 歐幾里得演算法)

ACM基礎演算法複習(STL + DFS + BFS + 並查集 + 快速冪 + 歐幾里得演算法)

從進隊到現在,師哥們陸陸續續講了很多基礎演算法,對我這種菜雞而言沒有什麼基礎,感覺都挺難的,所以還是複習複習,看看還有多少沒還給師哥的。。。

上課的內容大致有以下幾個模組(C語言基礎和python姑且不算)
1. STL
2. DFS + BFS
3. 並查集
4. 快速冪 + 歐幾里得演算法

1.STL之vector
把搜到關於vector的基本知識點列一下
1.push_back 在陣列的最後新增一個數據

2.pop_back 去掉陣列的最後一個數據

3.at 得到編號位置的資料

4.begin 得到陣列頭的指標

5.end 得到陣列的最後一個單元+1的指標

6.front 得到陣列頭的引用

7.back 得到陣列的最後一個單元的引用

8.max_size 得到vector最大可以是多大

9.capacity 當前vector分配的大小

10.size 當前使用資料的大小

11.resize 改變當前使用資料的大小,如果它比當前使用的大,者填充預設值

12.reserve 改變當前vecotr所分配空間的大小

13.erase 刪除指標指向的資料項

14.clear 清空當前的vector

15.rbegin 將vector反轉後的開始指標返回(其實就是原來的end-1)

16.rend 將vector反轉構的結束指標返回(其實就是原來的begin-1)

17.empty 判斷vector是否為空

18.swap 與另一個vector交換資料

vector c.
c.clear() 移除容器中所有資料。

c.empty() 判斷容器是否為空。

c.erase(pos) 刪除pos位置的資料

c.erase(beg,end) 刪除[beg,end)區間的資料

c.front() 傳回第一個資料。

c.insert(pos,elem) 在pos位置插入一個elem拷貝

c.pop_back() 刪除最後一個數據。

c.push_back(elem) 在尾部加入一個數據。

c.resize(num) 重新設定該容器的大小

c.size() 回容器中實際資料的個數。
c.begin() 返回指向容器第一個元素的迭代器
c.end() 返回指向容器最後一個元素的迭代器

關於vector的用法我只能算了解,以後多做題多積累
這裡掛一道oj上剛做的題
sdnu 1057 樹的查詢
Description
給定 n(1 <= n <= 1000000), m(1 <= m <= 10) 分別表示一棵樹中節點的個數及查詢的數量,每個節點的編號為給定的順序,之後給定每個節點的父節點編號,及 m 個查詢,每個查詢中,給定一個節點編號,對於每個查詢,按編號從小到大輸出該節點所有子節點。
Input
第一行兩個整數n, m,之後n行,每行兩個整數a, b,表示編號為a的節點的父節點是b,b為0表示沒有父節點,資料保證編號為1至n的節點均在a位置出現一次,之後一行m個整數,表示每個查詢要查詢的節點編號。
Output
m行,每行若干個從小到大排好序的、用一個空格隔開的整數,表示該次查詢的節點的所有子節點。
Sample Input
5 1
1 0
4 1
2 1
5 1
3 1
1
Sam Output
2 3 4 5

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
vector<int>v[1010010];
int main()
{
    int n,m;
    int a,b;
    int first;
    scanf("%d%d",&n,&m);
    for(int i = 0; i < n; i ++)
        {
            cin>>a>>b;
            if(b == 0)continue;
            v[b].push_back(a);

        }
    while(m--)
    {
        cin>>a;
        first = 1;
        for(int j = 0; j < v[a].size(); j ++)
        sort(v[a].begin(),v[a].end());
        for(int j = 0; j < v[a].size(); j ++)
        {
            if(first == 1)
            {
                cout<<v[a][j];
                first = 0;
                continue;
            }
            cout<<' '<<v[a][j];
        }
        cout<<endl;
    }
    return 0;
}

都是基礎用法就不解釋了,很水。
這算複習完vector?那接下來stack,map,queue就不一個一個找題了,和vector有很多共性,一定要多積累。

SET基本操作:
begin()    ,返回set容器的第一個元素
end()      ,返回set容器的最後一個元素
clear()    ,刪除set容器中的所有的元素
empty()    ,判斷set容器是否為空
max_size()   ,返回set容器可能包含的元素最大個數
size()      ,返回當前set容器中的元素個數
rbegin     ,返回的值和end()相同
rend()     ,返回的值和rbegin()相同

QUEUE基本操作:
back()返回最後一個元素
empty()如果佇列空則返回真
front()返回第一個元素
pop()刪除第一個元素
push()在末尾加入一個元素
size()返回佇列中元素的個數
queue入隊,如例:q.push(x); 將x 接到佇列的末端。
queue出隊,如例:q.pop(); 彈出佇列的第一個元素,注意,並不會返回被彈出元素的值。
訪問queue隊首元素,如例:q.front(),即最早被壓入佇列的元素。
訪問queue隊尾元素,如例:q.back(),即最後被壓入佇列的元素。
判斷queue佇列空,如例:q.empty(),當佇列空時,返回true。
訪問佇列中的元素個數,如例:q.size()

STACK基本操作
stack 的基本操作有:
入棧,如例:s.push(x);
出棧,如例:s.pop();注意,出棧操作只是刪除棧頂元素,並不返回該元素。
訪問棧頂,如例:s.top()
判斷棧空,如例:s.empty(),當棧空時,返回true。
訪問棧中的元素個數,如例:s.size()

MAP基本操作:
pair型別是在有檔案utility中定義的,pair型別包含了兩個資料值,通常有以下的一些定義和初始化的一些方法:
pair

/** 
 * DFS核心虛擬碼 
 * 前置條件是visit陣列全部設定成false 
 * @param n 當前開始搜尋的節點 
 * @param d 當前到達的深度 
 * @return 是否有解 
 */  
bool DFS(Node n, int d){  
    if (isEnd(n, d)){//一旦搜尋深度到達一個結束狀態,就返回true  
        return true;  
    }  

    for (Node nextNode in n){//遍歷n相鄰的節點nextNode  
        if (!visit[nextNode]){//  
            visit[nextNode] = true;//在下一步搜尋中,nextNode不能再次出現  
            if (DFS(nextNode, d+1)){//如果搜尋出有解  
                //做些其他事情,例如記錄結果深度等  
                return true;  
            }  

            //重新設定成false,因為它有可能出現在下一次搜尋的別的路徑中  
            visit[nextNode] = false;  
        }  
    }  
    return false;//本次搜尋無解  
}  

該模板轉載自:[email protected]

bfs模板:

/** 
 * 廣度優先搜尋 
 * @param Vs 起點 
 * @param Vd 終點 
 */  
bool BFS(Node& Vs, Node& Vd){  
    queue<Node> Q;  
    Node Vn, Vw;  
    int i;  

    //初始狀態將起點放進佇列Q  
    Q.push(Vs);  
    hash(Vw) = true;//設定節點已經訪問過了!  

    while (!Q.empty()){//佇列不為空,繼續搜尋!  
        //取出佇列的頭Vn  
        Vn = Q.front();  

        //從佇列中移除  
        Q.pop();  

        while(Vw = Vn通過某規則能夠到達的節點){  
            if (Vw == Vd){//找到終點了!  
                //把路徑記錄,這裡沒給出解法  
                return true;//返回  
            }  

            if (isValid(Vw) && !visit[Vw]){  
                //Vw是一個合法的節點並且為白色節點  
                Q.push(Vw);//加入佇列Q  
                hash(Vw) = true;//設定節點顏色  
            }  
        }  
    }  
    return false;//無解  
}  

找兩道題做做?

哎。。太菜了。。找一道入門題做做
dfs入門題:
Description:
現給定一個含有n個元素的陣列A,要求:從這n個數中選擇一些數,這些數的和恰好為k
Input:
多組測試資料。第一行為n(1<=n<=20) 第二行為n個整數,每個數的範圍為(-10^8≤A[i]≤10^8) 第三行為整數k(-10^8≤k≤10^8).
Output:
如果能夠達到目的,輸出”Of course,I can!”; 否則輸出”Sorry,I can’t!”.
Sample Input:
4
1 2 4 7
13
4
1 2 4 7
15
Sample Output:
Of course,I can!
Sorry,I can’t!

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int k,n;
int aa;
int a[1010];
int book[1010];
int dfs(int i, int sum)
{
    if(i < n && book[i] == 0)
    {
        book[i] = 1;

        if(sum + a[i] == k)return aa = 1;
        else if(sum + a[i] < k)
        {
            dfs(i + 1, sum);
            dfs(i + 1, sum + a[i]);
        }
        else
            dfs(i + 1, sum);
        book[i] = 0;//**回溯時取消標記**
    }
    return aa;
}
int main()
{

    while(scanf("%d",&n)!=EOF)
    {
        for(int i = 0; i < n; i ++)
            scanf("%d",&a[i]);
        scanf("%d",&k); aa = 0;
        memset(book,0,sizeof(book));
        if(dfs(0, 0))cout<<"Of course,I can!"<<endl;
        if(!dfs(0, 0)) cout<<"Sorry,I can't!"<<endl;

    }
    return 0;
}

基礎題目,思路簡單(還是做了好久啊。。),記得利用好標記,就是回過頭來複習複習。。。

然後是dfs基礎題目:
之前做過的一道電梯問題。。複習一下吧
There is a strange lift.The lift can stop can at every floor as you want, and there is a number Ki(0 <= Ki <= N) on every floor.The lift have just two buttons: up and down.When you at floor i,if you press the button “UP” , you will go up Ki floor,i.e,you will go to the i+Ki th floor,as the same, if you press the button “DOWN” , you will go down Ki floor,i.e,you will go to the i-Ki th floor. Of course, the lift can’t go up high than N,and can’t go down lower than 1. For example, there is a buliding with 5 floors, and k1 = 3, k2 = 3,k3 = 1,k4 = 2, k5 = 5.Begining from the 1 st floor,you can press the button “UP”, and you’ll go up to the 4 th floor,and if you press the button “DOWN”, the lift can’t do it, because it can’t go down to the -2 th floor,as you know ,the -2 th floor isn’t exist.
Here comes the problem: when you are on floor A,and you want to go to floor B,how many times at least he has to press the button “UP” or “DOWN”?
Input
The input consists of several test cases.,Each test case contains two lines.
The first line contains three integers N ,A,B( 1 <= N,A,B <= 200) which describe above,The second line consist N integers k1,k2,….kn.
A single 0 indicate the end of the input.
Output
For each case of the input output a interger, the least times you have to press the button when you on floor A,and you want to go to floor B.If you can’t reach floor B,printf “-1”.
Sample Input
5 1 5
3 3 1 2 5
0
Sample Output
3

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>

using namespace std;
int a[300];
int boo[1000];
int b[300];
int n;
int bfs(int s,int e)
{
    int h;
    memset(b,0,sizeof(0));
    boo[s]=1;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        h=q.front();
        q.pop();
        if(h==e)return b[h];

        if(h+a[h]<=n&&boo[h+a[h]]==0)
        {
            b[h+a[h]]=b[h]+1;
            boo[h+a[h]]=1;
            q.push(h+a[h]);
        }
        if(h-a[h]>=1&&boo[h-a[h]]==0)
        {
            b[h-a[h]]=b[h]+1;
            boo[h-a[h]]=1;
            q.push(h-a[h]);
        }
    }
    return -1;
}

int main()
{
    int s,e;
    while(cin>>n)
    {
        if(n==0)break;
        cin>>s>>e;
        memset(boo,0,sizeof(boo));
        memset(b,0,sizeof(b));
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        cout<<bfs(s,e)<<endl;
    }
    return 0;
}

多積累,我還是太菜了,這種問題都要琢磨半天。

接下來就是並查集了吧,聽強哥說這是找老大的問題,就是這樣吧。。。

主要是定義 find + join 兩個函式。。。帶權並查集還不是很會,簡單的並查集還可以

直接上題吧。。。
還是基礎題,感覺並查集是一個套路的呢
某省調查城鎮交通狀況,得到現有城鎮道路統計表,表中列出了每條道路直接連通的城鎮。省政府“暢通工程”的目標是使全省任何兩個城鎮間都可以實現交通(但不一定有直接的道路相連,只要互相間接通過道路可達即可)。問最少還需要建設多少條道路?
Input
測試輸入包含若干測試用例。每個測試用例的第1行給出兩個正整數,分別是城鎮數目N ( < 1000 )和道路數目M;隨後的M行對應M條道路,每行給出一對正整數,分別是該條道路直接連通的兩個城鎮的編號。為簡單起見,城鎮從1到N編號。
注意:兩個城市之間可以有多條道路相通,也就是說
3 3
1 2
1 2
2 1
這種輸入也是合法的
當N為0時,輸入結束,該用例不被處理。
Output
對每個測試用例,在1行裡輸出最少還需要建設的道路數目。
Sample Input
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0
Sample Output
1
0
2
998

Huge input, scanf is recommended.
先寫一個之前看大佬寫的非常規的
把所有人的父親都定義為 -1
然後join find。。。
最後所有“老大”的父親都是 -1,不是老大的人的父親不是-1
此時只要找有多少-1就知道有多少老大了,很神奇。。。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int pre[10000];
int find(int a)
{
    if(pre[a]==-1) return a;
    return pre[a] = find(pre[a]);
}
void join(int b,int c)
{
    int i=find(b);
    int j=find(c);
    if(i!=j) pre[i]=j;
}

int main()
{
    int m,n,i,a,b,sum;
    while(scanf("%d",&n)!=EOF&&n!=0)
    {
        scanf("%d",&m);
        for(i = 1; i <= n; i ++)pre[i]=-1;
        while(m--)
        {
            scanf("%d %d",&a,&b);
            join(a,b);
        }
        sum=0;
        for(i = 1;i<=n;i++)
            if(pre[i]==-1)
            sum++;
        printf("%d\n",sum-1);
    }
    return 0;
}

然後常規寫法
所有人的父親開始都是自己
其實和上面的一樣。。沒什麼不一樣吧。。就看看自己的父親還是不是自己就好了。。其實完全一樣的。。
懶得寫了從網上找個程式碼吧,。。。

#include<iostream>  
using namespace std;  

const int MAX=1000;  
int father[MAX];  

void initial(int n)    //初始化  
{  
    for(int i=1;i<=n;i++)  
        father[i]=i;  
}  

int find(int x)    //查詢  
{  
    while(father[x]!=x)  
        x=father[x];  

    return x;  
}  

void combine(int a,int b)   //合併  
{  
    int tmpa=find(a);  
    int tmpb=find(b);  

    if(tmpa!=tmpb)  
        father[tmpa]=tmpb;  
}  

int main()  
{  
    int i,n,m,a,b,tmp;  

    while(cin>>n,n)  
    {  
        initial(n);  

        cin>>m;  

        for(i=1;i<=m;i++)  
        {  
            cin>>a>>b;  
            combine(a,b);  
        }  

        tmp=0;  
        for(i=1;i<=n;i++)   //確定連通分量個數  
        {  
            if(father[i]==i)  
                tmp++;  
        }  

        cout<<tmp-1<<endl;  
    }  

    return 0;  
}  

你看我就說一樣吧。。。

帶權並查集好想要用到向量。。。然後就是向量關係。。然後過一陣再學學,先不寫這個。。

然後就是最近講的快速冪了
這真的是不難實現。。但是想用精應該也是不容易(因為我見過比較變態的題)
基本實現方法:
以下以求a的b次方來介紹[1]
把b轉換成二進位制數。
該二進位制數第i位的權為
2^(i-1)

例如

11的二進位制是1011
11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1
因此,我們將a¹¹轉化為算 a^2^0 + a^2^1 + a^2^3

b & 1//取b二進位制的最低位,判斷和1是否相同,相同返回1,否則返回0,可用於判斷奇偶

b>>1//把b的二進位制右移一位,即去掉其二進位制位的最低位

快速冪有遞迴實現,但是就學最快的最簡潔就好了吧

int pow(int a,int b){
  int r=1,base=a;
  while(b){
    if(b&1) r*=base;
    base*=base;
    b>>=1;
  }
  return r;
}

然後聽強哥的,數比較大的話能取模時就取模。。。

寫的是不是有點簡單了??
不管了反正還有一個就寫完了。。。

歐幾里得演算法:

歐幾里德演算法又稱輾轉相除法,是指用於計算兩個正整數a,b的最大公約數。應用領域有數學和計算機兩個方面。計算公式gcd(a,b) = gcd(b,a mod b)
其實記住這個公式就好了吧,但是理解原理更好,所以附上證明:

證法一
a可以表示成a = kb + r(a,b,k,r皆為正整數,且r

//功能:利用歐幾里德演算法,求整數a,b的最大公約數
//引數:整數a,b
//返回:a,b的最大公約數
int gcd(int a, int b){
if(a < b){ //保證a大於等於b,便於a%b的運算
int temp;
temp = a;
a = b;
b = temp;
}
while(a % b){ //如果餘數不為0,就一直進行輾轉相除
int r = a % b; //r為a和b的餘數,即r = a mod(b);
a = b;
b = r;
r = a % b;
}
return b;
}

也算比較簡單?
但是擴充套件歐幾里得演算法就不太懂了。。。
其實也能懂,不知道怎麼才能用得到而已。。。
強哥只講了用它解方程。
那就用它來解方程吧!

求解 x,y的方法的理解
設 a>b。
1,顯然當 b=0,gcd(a,b)=a。此時 x=1,y=0;
2,a>b>0 時
設 ax1+ by1= gcd(a,b);
bx2+ (a mod b)y2= gcd(b,a mod b);
根據樸素的歐幾里德原理有 gcd(a,b) = gcd(b,a mod b);
則:ax1+ by1= bx2+ (a mod b)y2;
即:ax1+ by1= bx2+ (a - [a / b] * b)y2=ay2+ bx2- [a / b] * by2;
說明: a-[a/b]*b即為mod運算。[a/b]代表取小於a/b的最大整數。
也就是ax1+ by1 == ay2+ b(x2- [a / b] *y2);
根據恆等定理得:x1=y2; y1=x2- [a / b] *y2;
這樣我們就得到了求解 x1,y1 的方法:x1,y1 的值基於 x2,y2.
上面的思想是以遞迴定義的,因為 gcd 不斷的遞迴求解一定會有個時候 b=0,所以遞迴可以結束。
擴充套件歐幾里德演算法
擴充套件歐幾里德演算法是用來在已知a, b求解一組x,y使得ax+by = Gcd(a, b) =d(解一定存在,根據數論中的相關定理)。擴充套件歐幾里德常用在求解模線性方程及方程組,下面是一個使用C++的實現:

int exGcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;y=0;
        return a;
    }
    int r=exGcd(b,a%b,x,y);
    int t=x;x=y;y=t-a/b*y;
    return r;
}

emmm
END。。。

終於搞完了?多看幾遍多看幾遍多看幾遍。。。
高數還沒學好就來搞機,搞機也沒搞好,很傷心
傷心歸傷心,還是要接著搞啊

這學期師哥不講課了,接下來多搞高數吧,因為一直在搞機,高數怕是要掛科了。。。

真叫人頭大
!!!

相關推薦

ACM基礎演算法複習STL + DFS + BFS + + 快速 + 演算法

從進隊到現在,師哥們陸陸續續講了很多基礎演算法,對我這種菜雞而言沒有什麼基礎,感覺都挺難的,所以還是複習複習,看看還有多少沒還給師哥的。。。 上課的內容大致有以下幾個模組(C語言基礎和python姑且不算) 1. STL

演算法複習——擴充套件演算法擴充套件,逆元,整除

①歐幾里得演算法 就是求gcd的有趣的輾轉相除法,不再贅述啦0v0 程式碼: int gcd(int a,int b) { if(b==0) return a; else return gcd(b,a%b); } ②擴充套件歐幾里得演算法 需要解決這樣的問題:兩個非0整數a,b

同餘定理演算法

如果  (a-b)%m==0  那麼 a%m==0  b%m==0 a,b關於模m同餘。   求最大公約數 #include "pch.h" #include<iostream> #include<cstdio> #include<

POJ-1061-青蛙的約會 擴充套件演算法

原題連結: http://poj.org/problem?id=1061 兩隻青蛙在網上相識了,它們聊得很開心,於是覺得很有必要見一面。它們很高興地發現它們住在同一條緯度線上,於是它們約定各自朝西跳,直到碰面為止。可是它們出發之前忘記了一件很重要的事情,既沒有問清楚對方的特徵,也沒有約定

C語言輾轉相除/相減法演算法求最大公約數和最小公倍數

#include <stdio.h> #include <stdlib.h> //題目:輸入兩個正整數m和n,求其最大公約數和最小公倍數。 //採用任何兩種演算法來完成上述題目,並比較2種演算法的時間複雜度和空間複雜度。 int main() { int

HDU-2669-Romantic 擴充套件演算法

原題連結: http://acm.hdu.edu.cn/showproblem.php?pid=2669 The Sky is Sprite. The Birds is Fly in the Sky. The Wind is Wonderful. Blew Throw the Trees

POJ-2142-The Balance 擴充套件演算法

原題連結: Ms. Iyo Kiffa-Australis has a balance and only two kinds of weights to measure a dose of medicine. For example, to measure 200mg of aspiri

BZOJ ~ 1385 ~ Division expression 演算法

題解 原式化為情況下最有可能。然後看能否把x2的約去即可。當然不能把上面那個數字乘出來了,它太大了,所以我們拿上面的每一個數字和x2去約GCD即可。 #include<bits/stdc+

poj 1061 青蛙的約會​​​​​​​拓展演算法

【題目】 【題意】 兩隻青蛙在給定長度的數軸上運動,給定初始位置和跳躍每次的長度,問在什麼時候兩隻青蛙能相遇。 【思路】 根據題意有x+mt=y+nt+kl,t表示跳躍次數。變化一下得到式子

兩個數的生成範圍兩個生成元拓展演算法

最近遇到一個題,就是給兩個數,這兩個數有無限個,問你由這些數能得到哪些數。 還可以擴充套件成有n個數,問你能得到哪些數 這裡其實是有一個結論的,就是: ①兩個數互質,就可以生成很多很多數,而且從某個數開始就是連續的 ②兩個數不互質,生成的數一定是gcd(a,b)的

擴充套件演算法求乘法逆元

eg:求5關於模14的乘法逆元 15 = 5*2+1 5 = 4*1+1 說明5與14互素,存在5關於14的乘法逆元 1 = 5-4 = 5-(14-5*2)= 5*3-14 因此5關於模14的乘法逆元為3  a存在模b的乘法逆元的充要條件是gcd(a,b)= 1 互質

演算法學習——演算法&擴充套件演算法

最大公約數/歐幾里德演算法(gcd) 歐幾里德演算法又稱輾轉相除法,證明可以度娘。 個人簡單腦部就是a和b兩個數的模還是a和b的最大公約數 int型別  int gcd(int a, int b) {return a%b==0?b:gcd(b,a%b);} long l

學以致用——Java原始碼——最大公約數計算的普通演算法演算法的比較Greatest Common Divisor

Our life is frittered away by detail ... Simplify, simplify. by Henry Thoreau (美國哲學家亨利·梭羅說,我們的生活被瑣碎的細節消磨殆盡,要簡化,要簡化!) 所以,如果能夠找到現成的解決方案,我們就沒必要自己

各種密碼學演算法的GUI程式設計實現DES、AES、Present、擴充套件演算法、素性檢測

encryption-algorithm 各種密碼學演算法的 C# GUI程式設計實現,包含: DES AES Present 擴充套件歐幾里得演算法 素性檢測 最終的結果 DES加密 DES解密

求最大公約數——演算法JAVA

歐幾里得演算法 問題描述:給出兩個數m,n,求解這兩個數的最大公因數 由於演算法比較簡單,這裡不再贅述,我做的這個演算法是默認了m>n,如果是對於任意兩個數來說的話,我們這裡還需要一個比較大小。

解的個數直線上的點數論-擴充套件演算法

Description  已知x,y滿足如下條件:  ax+by+c=0 ; x1 <= x <= x2 ; y1 <= y <= y2 ; x,y均為整數。  其中:a,b,c,x1,x2,y1,y2 都是絕對值不超過 10^8 的整數。  求(x,

演算法輾轉相除法描述,證明和python實現

greatest common divisor 又稱輾轉相除法 演算法描述:給定兩個正整數m和n,求他們的最大公因子,即能夠同時整除m和n的最大正整數。 演算法步驟: 若m<n,那麼m↔n,為了確保m>n。 求m除以n得到的餘數r。 若r為0,演算法

Python程式碼筆記1輾轉相除法/演算法求最大公約數gcdm,n

歐幾里得演算法求最大公約數:輾轉相除法 具體做法:用較小數除較大數,再用出現的餘數(第一餘數)去除除數,再用出現的餘數(第二餘數)去除除數,如此反覆,直到最後餘數是0為止。如果是求兩個數的最大公約數,

擴充套件演算法乘法逆元 最小正整數解 直線上的整數點

參考資料: 本文證明過程來自百度百科和劉汝佳的演算法入門經典。 擴充套件歐幾里得演算法介紹: 前置知識:歐幾里得演算法(其實就是輾轉相除法,用於計算兩個整數a,b的最大公約數。) 歐幾里得演算法: 在開始之前,我們先說明幾個定理: gcd(a,b)=gcd(b,a

演算法(輾轉相除法)c++實現

歐幾里得演算法 歐幾里得演算法也叫輾轉相除法,是求兩個整數最大公約數的演算法。 當然也可以求最小公倍數。 演算法實現 其實演算法的實現原理就是,有整數a b兩個,每次求的一個數字r = a % b,然後把b放到a的位置,把r放到b的位置,遞迴呼叫。