藍橋杯--算法入門級題目及答案解析

寫在最前面:
本文中會出現大量的請查閱.請自學什麼的,不是我不講,本文是面向算法初學者和藍橋杯的文章,如果真的想看進階算法的也不會來看這些題目,所以不要介意,我這裏就算是拋磚引玉了,大佬勿噴,ACMEer繞道哈哈哈哈。

1.楊輝三角形

問題描述

楊輝三角形又稱Pascal三角形,它的第i+1行是(a+b)i的展開式的係數。
它的一個重要性質是:三角形中的每個數字等於它兩肩上的數字相加。
  
下面給出了楊輝三角形的前4行:
   1
  1 1
 1 2 1
1 3 3 1
給出n,輸出它的前n行。

輸入格式
輸入包含一個數n。

輸出格式
輸出楊輝三角形的前n行。每一行從這一行的第一個數開始依次輸出,中間使用一個空格分隔。請不要在前面輸出多餘的空格。

樣例輸入
4
樣例輸出
1
1 1
1 2 1
1 3 3 1

數據規模與約定
1 <= n <= 34

楊輝三角形入門的話就是考察代碼編寫,是個模擬題目,當數據量達到一定程度之後是組合數問題,可以使用盧卡斯定理,這裏是入門,暫且不提,有興趣可以去我博客數論查找!

#include <bits/stdc++.h>
using namespace std;
int s[1000], a[1000];

void print(int source[], int ans[], int now, int target) //狀態轉移
{
    for (int i = 0; i < now; i++)
    {
        i == 0 ? ans[i] = 1 : ans[i] = source[i] + source[i - 1];
        cout << ans[i] << "\t";
    }
    puts("");
    if (now == target)
        return;
    print(ans, source, now + 1, target);
}
int main()
{
    int n;
    cin >> n;
    print(s, a, 1, n);
}

2.字符串比較

問題描述
  給定兩個僅由大寫字母或小寫字母組成的字符串(長度介於110之間),它們之間的關係是以下4中情況之一:
  1:兩個字符串長度不等。比如 Beijing 和 Hebei
  2:兩個字符串不僅長度相等,而且相應位置上的字符完全一致(區分大小寫),比如 Beijing 和 Beijing
  3:兩個字符串長度相等,相應位置上的字符僅在不區分大小寫的前提下才能達到完全一致(也就是說,它並不滿足情況2)。比如 beijing 和 BEIjing
  4:兩個字符串長度相等,但是即使是不區分大小寫也不能使這兩個字符串一致。比如 Beijing 和 Nanjing
  編程判斷輸入的兩個字符串之間的關係屬於這四類中的哪一類,給出所屬的類的編號。
輸入格式
  包括兩行,每行都是一個字符串
輸出格式
  僅有一個數字,表明這兩個字符串的關係編號
樣例輸入
BEIjing
beiJing 
樣例輸出
3


直接可以討論用c++的string即可,相關的string操作:1.可以判等== 2.可以比較字典序 < 或 > 3.reserve反轉 4.length()判斷長度

#include <bits/stdc++.h>
using namespace std;
int compare(string s1,string s2)
{
    if(s1.length()==s2.length())
    {
        if(s1==s2)return 2;
        for(int i=0;i<s2.length();i++)
        {
            if(toupper(s1[i])!=toupper(s2[i])) return 4;
        }
        return  3;
    }
    else return 1;
}
int main()
{
    string s1,s2;
    cin>>s1>>s2;
    cout<<compare(s1,s2);
}

3.N皇后問題Plus

問題描述
  給定一個n*n的棋盤,棋盤中有一些位置不能放皇后。現在要向棋盤中放入n個黑皇后和n個白皇后,使任意的兩個黑皇后都不在同一行、同一列或同一條對角線上,任意的兩個白皇后都不在同一行、同一列或同一條對角線上。問總共有多少种放法?n小於等於8。
輸入格式
  輸入的第一行爲一個整數n,表示棋盤的大小。
  接下來n行,每行n個01的整數,如果一個整數爲1,表示對應的位置可以放皇后,如果一個整數爲0,表示對應的位置不可以放皇后。
輸出格式
  輸出一個整數,表示總共有多少种放法。
樣例輸入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
樣例輸出
2
樣例輸入
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
樣例輸出
0

解析
N皇后問題,是一類搜索問題,這裏我們使用4個數組來保證米字的形狀沒有皇后,斜線的保存我們要發現一條左斜線的橫座標減縱座標是相同的,同一右斜線上的點橫縱座標相加的值相同,由此我們可以推理出以下搜索策略

#include <bits/stdc++.h>
using namespace std;
int mp[10][10];
int hen[10], shu[10], zuo[100], you[100];
int ans = 0;
void js(int len, int cen)
{
    if (cen == len)
    {
        ans++;
        return;
    }
    // puts("--------------------------------------------------------\n");
    // for (int i = 0; i < len; i++)
    // {
    //     for (int j = 0; j < len; j++)
    //     {
    //         cout<< mp[i][j]<<" ";
    //     }
    //     puts("");
    // }
    for (int i = 0; i < len; i++)
    {
        if (hen[i] == 0 && shu[i] == 0 && zuo[(cen + i) / 2] == 0 && you[cen - i + len] == 0 && mp[cen][i])
        {
            mp[cen][i] = 0;
            hen[i] = shu[i] = zuo[(cen + i + 1) / 2] = you[cen - i + len] = 1;
            js(len, cen + 1);
            mp[cen][i] = 1;
            hen[i] = shu[i] = zuo[(cen + i + 1) / 2] = you[cen - i + len] = 0;
        }
    }
    return;
}
int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
        {
            cin >> mp[i][j];
        }
    js(n, 0);
    cout << ans << endl;
}

4.導彈攔截

問題描述
  某國爲了防禦敵國的導彈襲擊,發展出一種導彈攔截系統。但是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能高於前一發的高度。某天,雷達捕捉到敵國的導彈來襲。由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的導彈。

  輸入導彈依次飛來的高度(雷達給出的高度數據是不大於30000的正整數),計算這套系統最多能攔截多少導彈,如果要攔截所有導彈最少要配備多少套這種導彈攔截系統。
輸入格式
  一行,爲導彈依次飛來的高度
輸出格式
  兩行,分別是最多能攔截的導彈數與要攔截所有導彈最少要配備的系統數

樣例輸入
389 207 155 300 299 170 158 65

樣例輸出
6
2

這是一類動態規劃問題,LIS問題。
第一問是求一個數列的最長下降子序列,第二問則是最長的非嚴格上升子序列(如3 3 2 1,可以相等)因爲最長上升子序列的每一個高度都需要一套攔截系統,彼此獨立。

#include <bits/stdc++.h>
using namespace std;
int h[1000];
int dp[1000][2];
map<int,int> cou;
pair<int,int> Lis(int a[],int len)
{
    int ans=0,cnt=0;
    for(int i=0;i<len;i++)
    {
        for(int j=0;j<i;j++)
        {
            if(h[j]<h[i]) dp[i][0]=max(dp[i][0],dp[j][0]+1);
            else dp[i][1]=max(dp[i][1],dp[j][1]+1);
            ans=max(ans,dp[i][0]);
            cnt=max(cnt,dp[i][1]);
        }
         
    }
    return make_pair(ans+1,cnt+1);
}
int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> h[i];
    auto answ=Lis(h,n);
    cout<<answ.first<<" "<<answ.second <<endl;
    
}

5.Fibonacci數列

問題描述

Fibonacci數列的遞推公式爲:Fn=Fn-1+Fn-2,其中F1=F2=1。

當n比較大時,Fn也非常大,現在我們想知道,Fn除以10007的餘數是多少。
輸入格式
輸入包含一個整數n。
輸出格式
輸出一行,包含一個整數,表示Fn除以10007的餘數。

說明:在本題中,答案是要求Fn除以10007的餘數,因此我們只要能算出這個餘數即可,而不需要先計算出Fn的準確值,再將計算的結果除以10007取餘數,直接計算餘數往往比先算出原數再取餘簡單。
樣例輸入
10
樣例輸出
55
樣例輸入
22
樣例輸出
7704
數據規模與約定
1 <= n <= 1,000,000

因爲是入門,藍橋杯也考不了這麼難,這裏寫遞推。如果有興趣進階的話,可以研究下,矩陣快速冪,和母函數的做法,我博客裏應該都有!

#include <bits/stdc++.h>
using namespace std;
const int MOD=10007;
int f[100000];
int init(int n)
{
    f[1]=f[2]=1;
    for(int i=3;i<=n;i++)
    f[i]=f[i-1]+f[i-2]%MOD;
}
int main()
{
    int n;
    cin>>n;
    init(n);
    cout<<f[n]<<endl;
}

6.校門外的樹

問題描述
  某校大門外長度爲L的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是1米。我們可以把馬路看成一個數軸,馬路的一端在數軸0的位置,另一端在L的位置;數 軸上的每個整數點,即012,……,L,都種有一棵樹。
  由於馬路上有一些區域要用來建地鐵。這些區域用它們在數軸上的起始點和終止點表示。已 知任一區域的起始點和終止點的座標都是整數,區域之間可能有重合的部分。現在要把這些區域中的樹(包括區域端點處的兩棵樹)移走。你的任務是計算將這些樹 都移走後,馬路上還有多少棵樹。

輸入格式
  輸入文件的第一行有兩個整數L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表馬路的長度,M代表區域的數目,L和M之間用一個空格隔開。接下來的M行每行包含兩個不同的整數,用一個空格隔開,表示一個區域的起始點 和終止點的座標。
輸出格式
  輸出文件包括一行,這一行只包含一個整數,表示馬路上剩餘的樹的數目。

樣例輸入
500 3
150 300
100 200
470 471
樣例輸出
298

數據規模和約定
  對於20%的數據,區域之間沒有重合的部分;
  對於其它的數據,區域之間有重合的情況。

這道題很簡單是簽到題,就是考察的模擬,會不會處理區間重疊情況,這道題的進階做法是差分,有興趣的可以查閱,我們這裏只是藍橋杯和入門

#include <bits/stdc++.h>
using namespace std; 
int a[1000000];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int l,r;
        cin>>l>>r;
        for(int j=l;j<=r;j++)
        {
            a[j]=-1;
        }
    }
    int ans=0;
    for(int i=0;i<=n;i++)
        if(a[j]==0) ans++;
    cout<<ans<<endl;
    

}

7.奪寶奇兵

算法提高 奪寶奇兵  
時間限制:1.0s   內存限制:512.0MB
    
[題目描述]
  在一座山上,有很多很多珠寶,它們散落在山底通往山頂的每條道路上,不同道路上的珠寶的數目也各不相同.下圖爲一張藏寶地圖:

  7
  3 8
  8 1 0
  2 7 4 4
  4 5 2 6 5

  ”奪寶奇兵”從山下出發,到達山頂,如何選路才能得到最多的珠寶呢?在上圖所示例子中,按照5->7->8->3->7的順序,將得到最大值30

[輸入]
  第一行正整數N(100>=N>1),表示山的高度
  接下來有N行非負整數,第i行有i個整數(1<=i<=N),表示山的第i層上從左到右每條路上的珠寶數目

[輸出]
  一個整數,表示從山底到山頂的所能得到的珠寶的最大數目.
[樣例輸入]
5
7
3 8
8 1 0 
2 7 4 4
4 5 2 6 5

[樣例輸出]
  30


經典DP算法,可以自下而上也可以從上向下,每次只保留最優的選擇方案,狀態轉移方程爲:
dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + mountain[i][j];

#include <bits/stdc++.h>
using namespace std;
int mountain[MAXN][MAXN];
int dp[MAXN + 1][MAXN + 1];

int main()
{

    cin>>n;
    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j <= i; ++j)
            cin>>mountain[i][j];
    }
    for (int i = N - 1; i >= 0; --i)
    {
        for (int j = 0; j <= i; ++j)
        {
            dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + mountain[i][j];
        }
    }
    cout<<dp[0][0]<<endl;
}

8.質因數分解

 基礎練習 分解質因數  
時間限制:1.0s   內存限制:512.0MB
    
問題描述
  求出區間[a,b]中所有整數的質因數分解。
輸入格式
  輸入兩個整數a,b。
輸出格式
  每行輸出一個數的分解,形如k=a1*a2*a3...(a1<=a2<=a3...,k也是從小到大的)(具體可看樣例)
樣例輸入
3 10
樣例輸出
3=3
4=2*2
5=5
6=2*3
7=7
8=2*2*2
9=3*3
10=2*5
提示
  先篩出所有素數,然後再分解。
數據規模和約定
  2<=a<=b<=10000

因爲是對區間進行分解,那麼質因數將會用到很多次,我們不能每一次都進行試除法,所以預先達標保留,我這裏只用了一次試除法,每次對求出小於右端點的所有質因子,這裏用了一個小優化,一個數的一對因子不可能都大於他開根號,對於質數的篩法有埃式篩法和線性篩法我博客裏也有可以去看,寫到這裏真的用不着,時間給的很充足。

#include <bits/stdc++.h>
using namespace std;
int prime[10000], cnt = 0;
void init(int n)
{
    for (int i = 2; i < n; i++)
    {
        int flag = 0;
        for (int j = 2; j * j <= i; j++)
        {
            if (i % j == 0)
            {
                flag = 1;
                break;
            }
        }
        if (flag == 1)
            continue;
        else
        {
            prime[++cnt] = i;
        }
    }
}
void fj(int n)
{
    cout << n << "=";
    int flag = 0;
    for (int i = 1; prime[i] <= n; i++)
    {
        while (n % prime[i] == 0)
        {
            if (!flag)
            {
                flag = 1;
            }
            else
                cout << "*";
            cout << prime[i];
            n /= prime[i];
        }
    }
    puts("");
}
int main()
{
    int l, r;
    cin >> l >> r;
    init(r);
    for (int i = l; i <= r; i++)
    {
        fj(i);
    }
}

寫在最後:
我叫風骨散人,名字的意思是我多想可以不低頭的自由生活,可現實卻不是這樣。家境貧寒,總得向這個世界低頭,所以我一直在奮鬥,想改變我的命運給親人好的生活,希望同樣被生活綁架的你可以通過自己的努力改變現狀,深知成年人的世界裏沒有容易二字。目前是一名在校大學生,預計考研,熱愛編程,熱愛技術,喜歡分享,知識無界,希望我的分享可以幫到你!
如果有什麼想看的,可以私信我,如果在能力範圍內,我會發布相應的博文!
感謝大家的閱讀!😘你的點贊、收藏、關注是對我最大的鼓勵!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章