基礎算法(一)


首先必須得說本人對算法研究不深,一些簡單的就得想半天,老是這樣感覺不太好,遂記錄下一些常見的基礎算法,避免尷尬。不足之處請各位多多指教。

其次,用vs寫C語言程序時可能會出現如下錯誤:
錯誤 C4996 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

解決方法1:在代碼的開頭加上這句  #pragma warning(disable:4996)

解決方法2:在創建項目時按下圖進行選中:

最后,進入正題。。。

1.最大公約數

    01.短除法:我們小學學習的用來求最大公約數的方法,體現在代碼中主要的操作就是比較和累乘。

#include<stdio.h>
int main()
{
    int a, b, t, i;
    scanf("%d%d", &a, &b);
    t = 1;
    for (i = 2; i <=a&&i<=b; i++)
    {
        while (a%i==0&&b%i==0)
        {
            t = t*i;
            a = a / i;
            b = b / i;
        }
    }
    printf("Maximal common divisor is %d\n", t);
    return 0;
}

   02.輾轉相除法:它根據遞推策略設計的,求解效率更高。   

#include<stdio.h>
int main()
{
    int a, b,c;
    scanf("%d%d", &a, &b);//輸入的時候注意:a>b
    if (b==0)
    {
        printf("data error.\n");
        return 0;
    }
    else
    {
        c = a%b;
        while (c!=0)
        {
            a = b;
            b = c;
            c = a%b;
        }
    }
    
    printf("Maximal common divisor is %d\n", b);
    return 0;
}

    03相減法:兩數中的大數減小數,其差與減數再進行大數減小數,直到差與減數相等為止,此時的差或者減數就是最大公約數。

#include<stdio.h>
int main()
{
    int a, b, c;
    scanf("%d%d", &a, &b);//輸入的時候注意:a>b
    c = a - b;
    while (c!=b)
    {
        if (b > c)
        {
            a = b;
            b = c;
        }
        else
        {
            a=c;
        }
        c = a - b;
    }
    printf("Maximal common divisor is %d\n", b);
    return 0;
}

 

2.最小公倍數

  在我們已經求出最大公約數的情況下,再求最小公倍數就很容易了。下面給出的是短除法求得最大公約數之后求最小公倍數的方法:

#include<stdio.h>
int main()
{
    int a, b, t, i;
    scanf("%d%d", &a, &b);
    t = 1;
    for (i = 2; i <= a&&i <= b; i++)
    {
        while (a%i == 0 && b%i == 0)
        {
            t = t*i;
            a = a / i;
            b = b / i;
        }
    }
    printf("Minimal common multiple is %d\n", t*a*b);
    return 0;
}

 

3.素數

 這個好像有點尷尬,算法課上,老師點了兩個同學到黑板上去寫,然后兩個都寫得不太對。。。后來想想,作為大三,真的。。。可能是一時被點還有點沒反應過來吧。

#include<stdio.h>
#include<math.h>
int main()
{
    int k, n,i,x;
    while (scanf("%d", &x) != 0)
    {
        n = sqrt(x);
        i = 0;
        for (k = 2; k <= n; k++)
            if (x%k == 0)
            {
                i = 1;
                printf("%d is not a prime number.\n",x);
                break;
            }
        if (i == 0)
            printf("%d is  a prime number.\n", x);
    }
    return 0;
}

4.完數

   一個數如果恰好等於它的因子之和,這個數就稱為”完數“,6的因子為1,2,3,而6=1+2+3,所以6就是完數。

#include<stdio.h>
int main()
{
    int i, m, s;
    for (m = 2; m < 1000; m++)
    {
        s = 0;
        for (i = 1; i < m; i++)
            if (m%i == 0)
                s += i;
        if (s == m)
        {
            printf("%d,its factors are ", m);
            for (i = 1; i < m; i++)
                if (m%i == 0)
                    printf("%d ", i);
            printf("\n");
        }
    }
    return 0;
}

5.裴波那挈數列  

   裴波那挈數列具有以下特點:

        a1,a2已知

        a(n)=a(n-1)+a(n-2)  n>=3

   我們在很多地方都會遇到這個數列,比如兔子繁殖問題、樹枝問題、上樓方式問題、蜂房問題等等。我們既可以用遞推,也可以用遞歸的方法來解決。

//遞推
#include<stdio.h>
int main()
{
    int a = 1, b = 1;
    printf("%d %d ", a,b);
    while (a<5000)
    {
        a = a + b;
        b = a + b;
        printf("%d %d ", a, b);
    }

    return 0;
}

 

//遞歸
#include<stdio.h>
int f(int n)
{
    if (n == 1 || n == 2)
        return 1;
    else
        return f(n - 1) + f(n - 2);
}
int main()
{
    int i;
    for (i = 1; i < 20; i++)
        printf("%d ", f(i));
    printf("\n");
    return 0;
}

6.楊輝三角

 1

 1   1

 1   2   1

 1   3   3   1

 1   4   6   4   1

 ............................

 楊輝三角是(a+b)^n (n>=0)展開后各項的系數,具有以下規律:

 1.各行的第一個數和最后一個數都是1

 2.從第3行起,除第一個數和最后一個數外,其余各數是上一行同列和前一列兩個數之和。即a[i][j]=a[i-1][j]+a[i-1][j-1]  (i表示行數,j表示列數)

#include<stdio.h>
const int N = 10;
int main()
{
    int i, j;
    int a[N][N];
    for (i = 0; i < N; i++)
    {
        for (j = 0; j <=i; j++)
            if (j == 0 || j ==i)
                a[i][j] = 1;
            else 
                a[i][j] = a[i - 1][j] + a[i - 1][j - 1];
    }

    for (i = 0; i < N; i++)
    {
        for (j = 0; j <=i; j++)
            printf("%6d", a[i][j]);
        printf("\n");
    }

    return 0;
}

7.魔方陣

   魔方陣,它的每一行,每一列以及對角線上的各數之和為一個相同的常數。

   這里只考慮了奇次階魔方陣,數組下標是從1~n。

#include<stdio.h>
int main()
{
    int i, j, i1, j1, x, n, a[100][100];
    printf("input an odd number:");
    scanf("%d", &n);
    if (n % 2 == 0)
    {
        printf("input error!\n");
        return 0;
    }
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            a[i][j] = 0;

    i = 1;
    j = (int)(n+1)/ 2;
    x = 1;
    while (x <= n*n)
    {
        a[i][j] = x;
        x = x + 1;
        i1 = i;
        j1 = j;
        i = i -1;
        j = j - 1;
        if (i == 0) i = n;
        if (j == 0) j = n;
        if (a[i][j] != 0)
        {
            i = i1 + 1;
            j = j1;
        }
    }
        for (i = 1; i <= n; i++)
        {
            for (j = 1; j <= n; j++)
                printf("%5d", a[i][j]);
            printf("\n");
        }
}

 

8.漢諾塔問題

   簡單的說就是有A,B,C三個基座,要將A座上的盤子移動到B座,在移動的過程中3個基座上的盤子都必須保持大盤在下,小盤在上,可以利用C座做輔助。

   記得大一的時候,怎么都不太懂,那個時候好像題目都沒太讀懂,然后不理解遞歸,就一直害怕這個。

   我們把n個盤子抽象地看作是“兩個盤子”,上面一個由1~n-1號組成,下面一個就是第n號盤子,移動過程如下:

   1.先把上面一個盤子以A基座為起點借助B基座移動到C基座,

   2.把下面一個盤子從A基座移動到B基座,

   3.再把C基座上的一個盤子借助A基座移動到B基座。

#include<stdio.h>
void hanoi(int n, char a,char b,char c);
int main()
{
    int n;
    scanf("%d", &n);
    hanoi(n, 'A', 'B', 'C');
}

void hanoi(int n, char a, char b, char c)
{
    if (n > 0)
    {
        hanoi(n - 1, a, c, b);
        printf("Move dish %d from pile %c to %c.\n", n, a, b);
        hanoi(n - 1, c, b, a);
    }
}

9.整數的划分問題

   對於一個正整數的划分,就是把n表示成一系列正整數之和的表達式。例如n=6的划分如下:

   6

   5+1   

   4+2   4+1+1

   3+3   3+2+1   3+1+1+1

   2+2+2    2+2+1+1    2+1+1+1+1

   1+1+1+1+1+1

   問題:對於給定的正整數n,求出它划分的數目

   根據n=6的實例發現:第一行及以后的數據都不超過6,第二行及以后的數據都不超過5,......第六行的數據都不超過1.據此,定義一個函數Q(n,m),表示整數n的“任何加數都不超過m"的分划得數目,n的所有划分的數目就是Q(n,n)

   一般Q(n,m)有以下遞歸關系:

   Q(n,n)=1+Q(n,n-1)        

   Q(n,n)=Q(n,m-1)+Q(n-m,m)   (n>m)

  遞歸的停止條件:

  Q(n,1)=1

  Q(1,m)=1

#include<stdio.h>

int Divinteger(int n, int m);
int main()
{
    int n;
    scanf("%d", &n);
    if (n < 1)
    {
        printf("Input error!\n");
        return 0;
    }

    printf("%d\n", Divinteger(n, n));
}

int Divinteger(int n, int m)
{
    if (n == 1 || m == 1)
        return 1;
    else if (n < m)
        return Divinteger(n, n);
    else if (n == m)
        return 1 + Divinteger(n, n - 1);
    else
        return Divinteger(n, m - 1) + Divinteger(n - m, m);
}

 

10.開燈問題

   有從1到n依次編號的n個同學和n盞燈。1號同學將所有的燈都關掉,2號同學將編號為2的倍數的燈都打開,3號同學將編號為3的倍數的燈都關掉,.......以后的同學都將自己編號的倍數的燈做相反的處理。(該號燈如是打開的,則關掉;如關閉的,則打開)。問經n個同學操作后,哪些燈是打開的

   1.定義n個元素的a數組,它的每個下標變量a[i]視為一燈,i表示其編號。a[i]=1表示第i盞燈處於打開狀態,a[i]=0表示第i盞燈處於關閉狀態。

   2.通過算術運算a[i]=1-a[i](乒乓開關),模擬“開關”燈的操作。

#include<stdio.h>
int main()
{
    int n, a[1000], i, k;
    printf("input a number:");
    scanf("%d", &n);
    for (i = 1; i <=n; i++)
    {
        a[i] = 0;
    }
    for (i = 2; i <=n; i++)
    {
        k = 1;
        while (i*k<=n)
        {
            a[i*k] = 1 - a[i*k];
            k++;
        }
        for (i = 1; i <=n; i++)
        {
            if (a[i] == 1)
                printf("%d ",i);
        }
        printf("\n");
    }
}

好了,就到這里,下次見!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM