算法訓練(更新中。。。)


 ALGO-1007 印章(DP)

資源限制
時間限制:1.0s   內存限制:256.0MB
問題描述
  共有n種圖案的印章,每種圖案的出現概率相同。小A買了m張印章,求小A集齊n種印章的概率。
輸入格式
  一行兩個正整數n和m
輸出格式
  一個實數P表示答案,保留4位小數。
樣例輸入
2 3
樣例輸出
0.7500
數據規模和約定
1≤n,m≤20
方法一:
#include<iostream>
#include<iomanip>
#include<math.h>
using namespace std;
double dp[22];//一維數組,dp[i]:買i張印章,湊齊n種印章的概率 
/*為什么用一維數組?
因為在此解法所用的遞推公式中,
買m張印章,湊齊n種印章的概率只與買m張印章,湊齊n-1種,n-2種...1種 的概率有關 ,
與買x(x!=m)張印章湊齊y(y>=1)種印章的概率無關。
這是一個具體的問題,就是說明了買了m張,求的是里面剛好有n,這個事件的概率*/
long long c_fun(int n, int m)//求C(n,m),注意n為下標,m為上標
{
    long i;
    long long ans_n = 1, ans_m = 1, ans_nm = 1;
    for (i = 2; i <= n; i++)
        ans_n = ans_n * i;
    for (i = 2; i <= m; i++)
        ans_m = ans_m * i;
    for (i = 2; i <=(n-m) ; i++)
        ans_nm = ans_nm * i;
    return ans_n / (ans_m * ans_nm);
}
double fun(int n, int m)//dp[n],求印章問題,待求事件的概率
{
    int i, j;
    dp[1] = 1;//對於湊齊1種,只要買了概率的發生一定是1。
    for (i = 2; i <= n; i++)//這個循環求湊齊2、3、...n種的概率,后面一個數字發生的概率需要前一個發生的概率
    {
        double t = 0;        //i代表湊齊的種數,j的取值為1--m,
        for (j = 1; j < i; j++)//當j>i時,意味着買的印章數<湊齊的印章種數,此事件不可能發生
            t += c_fun(i, j) * pow(j, m) * dp[j];//求逆事件的概率
        dp[i] = 1 - t / pow(i, m);//總概率為1,1減去逆事件的概率為待求事件概率;
        //看到這一步,其實可以想到另一種方法直接求待求事件的概率;
    }
    return dp[n];
}
int main()
{
    int n, m;//n=湊齊的種數,m=買的印章數;
    cin >> n >> m;
    dp[n] = fun(n, m);
    cout << fixed<<setprecision(4)<< dp[n] << endl;
    return 0;
}

做這道題發現藍橋杯系統有bug誒,就算是通過了所有的測試,代碼的邏輯還是有問題的。不過這也是很正常的是,測試代碼是否正確他只看輸入輸出是否正確,只要通過那幾組測試,都沒啥大問題。

參考文章: 藍橋杯算法訓練 印章_!YI的博客-CSDN博客

方法二:

#include<iostream>
#include<math.h>
#include<iomanip>
using namespace std;
double dp[25][25] ;
int main()
{
    int n, m;
    cin >> n >> m;
    double p=1.0/n;//每種出現的概率,設一個double型的p也為方面了后面的運算,使運算結果為double型
    for (int i = 1; i <= m; i++)
    {
        dp[i][1] = pow(p, i - 1);//dp[i][1]=p^(n-1);
        for (int j = 2; j <= i; j++)
            dp[i][j] = dp[i-1][j - 1] * ((n-j+1)*p) + dp[i - 1][j]*(j*p);
        //((n-j+1)/n)  典型錯誤,計算結果為0
    /*我們買的第 i 張,有兩種狀態,一:跟前面買的 i - 1 張中有重復的 二:跟前面買的 i - 1 張中沒有重復的
        買第i張如果有重復的着事件發生的概率為dp[i - 1][j]*(j*p);
        如果沒有重復的則抽到第i與前面的種數有重復則事件發生的概率為dp[i-1][j - 1] * ((n-j+1)*p)
        注意是dp[i-1][j - 1] * ((n-j+1)*p)不是dp[i][j - 1] * ((n-j+1)*p),抽一張新的種類i、j都要+1,
        所以對於dp[i][j]的概率,是上面兩種可能概率相加*/
    }
    cout << fixed<<setprecision(4)<<dp[m][n] << endl;
    return 0;
}

其實這個方法可以設數組為一維數組,還有想說的是for循環yyds!!!

貼一下下面分享的博主寫的,他的for里面加了if語句,這個想法很好誒!

#include <iostream>
#include <cmath>
using namespace std;
double dp[25][25], p;
int main()
{
    
    //記住是小數啊,要*1.0進行類型轉換的
    int n, m;
    cin >> n >> m;
    p = 1.0 / n; //每種出現的概率
    
    for ( int i = 1; i <= m; ++i ) {
        for ( int j = 1; j <= n; ++j ) {
            if ( i <  j ) dp[i][j] = 0;
            if ( j == 1 ) {
                dp[i][j] = pow (p, i-1);  //p^(i-1)
            }
            else {
                dp[i][j] = dp[i-1][j] * (j*1.0/n) + dp[i-1][j-1] * ((n-j+1)*1.0/n);
            }
        }
    }
//    cout << "dp\n";
//        for ( int i = 1; i <= m; ++i ) {
//        for ( int j = 1; j <= n; ++j ) {
//            printf("%.2lf  ",dp[i][j]);
//        }
//        cout << endl;
//    }
    
    printf("%.4lf  ",dp[m][n]);
    return 0;
}

總結一下這個題考的就是數學,求概率,可惜我概率論學的撇啊!

參考文章: 藍橋杯 試題 算法訓練 印章_okok__TXF的博客-CSDN博客

ALGO-1006 拿金幣(DP)

資源限制
時間限制:1.0s   內存限制:256.0MB
問題描述
  有一個N x N的方格,每一個格子都有一些金幣,只要站在格子里就能拿到里面的金幣。你站在最左上角的格子里,每次可以從一個格子走到它右邊或下邊的格子里。請問如何走才能拿到最多的金幣。
輸入格式
  第一行輸入一個正整數n。
  以下n行描述該方格。金幣數保證是不超過1000的正整數。
輸出格式
  最多能拿金幣數量。
樣例輸入
3
1 3 3
2 2 2
3 1 2
樣例輸出
11
數據規模和約定
  n<=1000
#include<iostream>
using namespace std;
int dp[1002][1002] = { 0 };
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)//給一個位置賦值,值代表這個位置金幣的數量
        for (int j = 1; j <= n; j++)
            cin >> dp[i][j];
    for (int i = 1; i <= n; i++)//遍歷所有的位置,每一個位置的值都+=max(左邊或者上邊)
        for (int j = 1; j <= n; j++)//在草稿紙上面畫一哈,其實就可以確定走的路徑,
        {                           //對於dp[n][n]的值來說,它一定的走的所有路徑中所加值最大的那條路的值
            if (dp[i - 1][j] > dp[i][j - 1])
                dp[i][j] += dp[i - 1][j];
            else
                dp[i][j] += dp[i][j - 1];
        }
    cout << dp[n][n] << endl;//分析可知要使撿的金幣最多一定是走到了(n,n)這個位置的。
    return 0;
}

參考文章: LanQiao-ALGO-1006 拿金幣(動態規划) (類似 LeetCode 62.不同路徑)_Mr.xiao的博客-CSDN博客

感謝大佬的文章,這個題其實考了圖的知識。

ALGO-1005 數字游戲(搜索)

資源限制
時間限制:1.0s   內存限制:256.0MB
問題描述
  給定一個1~N的排列a[i],每次將相鄰兩個數相加,得到新序列,再對新序列重復這樣的操作,顯然每次得到的序列都比上一次的序列長度少1,最終只剩一個數字。
  例如:
  3 1 2 4
  4 3 6
  7 9
  16
  現在如果知道N和最后得到的數字sum,請求出最初序列a[i],為1~N的一個排列。若有多種答案,則輸出字典序最小的那一個。數據保證有解。
輸入格式
  第1行為兩個正整數n,sum
輸出格式
  一個1~N的一個排列
樣例輸入
4 16
樣例輸出
3 1 2 4
數據規模和約定
  0<n<=10
方法一:STL函數 next_permutation
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int c_fun(int a, int b)//求C(a,b)
{
    int ans_a = 1, ans_b = 1, ans_ab = 1;
    for (int i = 2; i <= a; i++)
        ans_a *= i;
    for (int i = 2; i <= b; i++)
        ans_b *= i;
    for (int i = 2; i <= a - b; i++)
        ans_ab *= i;
    return ans_a / (ans_b * ans_ab);
}
int main()
{
    int n, sum;
    cin >> n >> sum;
    vector<int> lst;
    for (int i = 1; i <= n; i++)
        lst.push_back(i);
    do {
        int temp = 0;
        for (int i = 0; i < n; i++)
            temp += lst[i] * c_fun(n - 1, i);//規律,正推推出來的 temp = a[0]*C(0,n-1) + a[1]*C(1,n-1) + ... +a[n-1]*C(n-1,n-1);
        if (sum == temp)//在if里面寫輸出語句保證了輸出結果存在則有輸出,不存在無輸出
        {
            for (vector<int>::iterator it = lst.begin(); it != lst.end(); it++)
                cout << *it << " ";
            break;
        }
    } while (next_permutation(lst.begin(), lst.end()));
    return 0;
}

參考文章: 藍橋杯 數字游戲 C++_m0_56318237的博客-CSDN博客     

方法二:dfs

dfs方法不是很好,下次來補充

ALGO-1004 無聊的逗

資源限制
時間限制:1.0s   內存限制:256.0MB
問題描述
  逗志芃在干了很多事情后終於閑下來了,然后就陷入了深深的無聊中。不過他想到了一個游戲來使他更無聊。他拿出n個木棍,然后選出其中一些粘成一根長的,然后再選一些粘成另一個長的,他想知道在兩根一樣長的情況下長度最長是多少。
輸入格式
  第一行一個數n,表示n個棍子。第二行n個數,每個數表示一根棍子的長度。
輸出格式
  一個數,最大的長度。
樣例輸入
4
1 2 3 1
樣例輸出
3
數據規模和約定
  n<=15
 方法一:dfs
#include<iostream>
#include<vector>
#include<numeric>
#include<algorithm>
using namespace std;
int maxLen = 0;
void dfs (vector<int>dp, int n, int add, int compare = 0, int scan = 0)
{
    if (scan >= n) return;//遞歸結束條件,遍歷完所有可能的結果
    //如果add==compare,且新計算得到的compare大於原來的maxLen,則更新maxLen;
    if (add == compare && maxLen < compare) maxLen = compare;
    //如果選擇scan這個位置的木棍來組成compare的值
    dfs(dp, n, add - dp[scan], compare + dp[scan], scan + 1);
    //如果不選則scan這個位置的木棍來組成compare的值
    dfs(dp, n, add, compare, scan + 1);
}
int main()
{
    int n, a = 0;
    cin >> n;
    vector<int>dp(n);
    for (int i = 0; i < n; i++)
        cin >> dp[i];
    int sum = accumulate(dp.begin(), dp.end(), 0);//計算所有木棍的總長度
    sort(dp.begin(), dp.end(), greater<int>());//逆序排
/*逆序排的好處?dp[0]存的為最大的值,方便后序處理。*/
    /*此題的輸入的棍子長度總數大概有三種情況,
    1.max==sum/2;
    2.max>sum/2,刪除最大值后再排,也就是掃描的位置可以直接從1開始。
    3.sum%2!=0,刪除最小奇數
    4.sum為偶數;  如果數能被分為兩堆一樣長,則這個數一定為偶數,
    所以我們要把范圍局限為偶數,偶數都沒法,這沒法分了*/
    if ((double)dp[0] == sum / 2.0)//1.
    {
        cout << dp[0];
        return 0;
    }
    //if 最大長度大於sum/2,則刪除最大長度木棍;
    if (dp[0] > sum / 2)//2.
        dfs(dp, n, sum - dp[0], a, 1);
    else if (sum % 2 != 0)//3.
    {
        for (int i = n - 1; i >= 0; i--)
            if (dp[i] % 2 != 0)
            {
                sum = sum - dp[i];
                for (int j = i; j < n - 1; j++)
                {
                    dp[j] = dp[j + 1];
                }
                n = n - 1;

                break;
            }
        dfs(dp, n, sum, a, 0);
    } else
    {
        dfs(dp, n, sum, a, 0);//4.
    }
    cout << maxLen << endl;
    return 0;
}

參考:藍橋杯 試題 算法訓練 無聊的逗 C++ 詳解_Lyz_ID的博客-CSDN博客

方法二.01背包

鏈接放下面,屬於是沒看懂,等今后再來看。

參考文章:LanQiao-ALGO-1004 無聊的逗 (動態規划: 0-1背包問題) -- (LeetCode 416. 分割等和子集 變種題)_Mr.xiao的博客-CSDN博客

ALGO-1003 禮物

資源限制
時間限制:1.0s   內存限制:256.0MB
問題描述
  JiaoShou在愛琳大陸的旅行完畢,即將回家,為了紀念這次旅行,他決定帶回一些禮物給好朋友。
  在走出了怪物森林以后,JiaoShou看到了排成一排的N個石子。
  這些石子很漂亮,JiaoShou決定以此為禮物。
  但是這N個石子被施加了一種特殊的魔法。
  如果要取走石子,必須按照以下的規則去取。
  每次必須取連續的2*K個石子,並且滿足前K個石子的重量和小於等於S,后K個石子的重量和小於等於S。
  由於時間緊迫,Jiaoshou只能取一次。
  現在JiaoShou找到了聰明的你,問他最多可以帶走多少個石子。
輸入格式
  第一行兩個整數N、S。
  第二行N個整數,用空格隔開,表示每個石子的重量。
輸出格式
  第一行輸出一個數表示JiaoShou最多能取走多少個石子。
樣列輸入
  8 3
  1 1 1 1 1 1 1 1
樣列輸出
  6
樣列解釋
  任意選擇連續的6個1即可。
數據規模和約定
  對於20%的數據:N<=1000
  對於70%的數據:N<=100,000
  對於100%的數據:N<=1000,000,S<=10^12,每個石子的重量小於等於10^9,且非負
方法:二分法
#include<iostream>
using namespace std;
int n;
long long s;
const int M = 1e6 + 10;//包括了所有數組取值大小
int weight[M];//每一個石頭的重量
long long suffix[M];//前i個石頭的重量和

bool check(int mid) {//mid的值是數組的下標,也表示了輸出石頭的個數
    for (int i = mid; i <= n - mid; i++) {
        if (suffix[i] - suffix[i - mid] <= s && suffix[i + mid] - suffix[i] <= s)
            //if 語句里面保證了前mid 個數小於s,后mid個數小於s ;
            return true;
    }
    return false;
}

int main() {
    cin >> n >> s;
    suffix[0] = 0;//給0位置賦值 0

    for (int i = 1; i <= n; i++) {
        cin >> weight[i];
        suffix[i] = suffix[i - 1] + weight[i];
    }

    int l, r, mid;
    l = 1;
    r = n;

    while (l <= r) {//二分法
        mid = (l + r) / 2;
        if (check(mid)) l = mid+1;
        else r = mid - 1;
    }

    cout << 2 * (l-1) << endl;//為什么l要-1呢?因為運行到l=r時肯定滿足條件,
    //此時循環繼續l的值變為l+1>r,調出循環,此時沒有進行cheak()運算。

    return 0;
}

ALGO-1002 跳馬

資源限制
時間限制:1.0s   內存限制:256.0MB
問題描述
  一個8×8的棋盤上有一個馬初始位置為(a,b),他想跳到(c,d),問是否可以?如果可以,最少要跳幾步?
輸入格式
  一行四個數字a,b,c,d。
輸出格式
  如果跳不到,輸出-1;否則輸出最少跳到的步數。
樣例輸入
1 1 2 3
樣例輸出
1
數據規模和約定
  0<a,b,c,d≤8且都是整數。
 方法:BFS
#include<iostream>
#include<queue>
using namespace std;
bool vis[9][9] = { 0 };//建立9*9的數組,其中(1-8)*(1-8)代表棋盤
//dx和dy一一對應,表示馬走一步代表的走法,共八種(0,0)不算
int dx[9] = { 0,-2,-2,-1,-1,1,1,2,2 }; 
int dy[9] = { 0,-1,1,-2,2,-2,2,-1,1 };
queue<node> q;//建立隊列q,用BFS肯定需要隊列輔助呀

/*建立一個節點,節點代表每一個點的坐標(x,y)
以及從初始位置走到此點需要走幾步*/
struct node
{
    int x, y;
    int step;
    node() :x(), y(), step() {};
    node(int a, int b, int c) :x(a), y(b), step(c) {};
};

int BFS_search(int a, int b, int c, int d)
{
    if (a == c && b == d)//如果目標點就是起始點
        return 0;
    vis[a][b] = true;//代表此點已經走過,修改值為true
    q.push(node(a, b, 0));//進入隊列
    while (!q.empty())
    {
        node t = q.front();//頭指針的值賦值給t;
        q.pop();//出隊
        for (int i = 1; i <= 8; i++)//廣度遍歷關鍵操作,把每一種走法走一遍
        {
            int cur_x = t.x + dx[i];
            int cur_y = t.y + dy[i];
            if (cur_x == c && cur_y == d)
            {
                return t.step + 1;
            }
            else if(cur_x>=1&&cur_x<=8&&cur_y>=1&&cur_y<=8&&!vis[cur_x][cur_y])
            {
                q.push(node(cur_x, cur_y, t.step + 1));
                vis[cur_x][cur_y] = true;
            }
        }
    }
    return -1;
}
int main()
{
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    cout << BFS_search(a, b, c, d);
    return 0;
}

參考:試題 算法訓練 跳馬_Solar_angel的博客-CSDN博客

 

ALGO-1001 kAc給糖果你吃(貪心)

資源限制
時間限制:1.0s   內存限制:256.0MB
問題描述
  kAc有n堆糖果,每堆有A[i]個。
  kAc說你只能拿m次糖果,聰明的你當然想要拿最多的糖果來吃啦啦啦~
  //第二天,kAc問你還想吃糖果么?(嘿嘿嘿)說着眼角路出奇怪的微笑...
輸入格式
  第一行兩個數字n和m,第二行有n個數字A[i]。
輸出格式
  輸出一行表示最多能拿幾個糖果。
樣例輸入
2 2
1 2
樣例輸出
3
數據規模和約定
  0<n≤1000
  其余數字都是不超過1,000,000,000的非負整數。
 
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main()
{
    int n, m;
    long long sum=0;
    cin >> n >> m;
    vector<long long> A(n);
    for (int i = 0; i < A.size(); i++)
         cin>> A[i];
    sort(A.begin(), A.end(), greater<long long>());//從大到小排
    for (int i = m,j=0; i > 0; i--,j++)//取的每一個數都是能取數中,最大的(貪心)
    {
        sum += A[j];
    }
    cout << sum;
    return 0;
}

這是我做過的算法題中最簡單的,沒有之一!

ALGO-999 數的潛能

資源限制
時間限制:1.0s   內存限制:256.0MB
問題描述
  將一個數N分為多個正整數之和,即N=a1+a2+a3+…+ak,定義M=a1*a2*a3*…*ak為N的潛能。
  給定N,求它的潛能M。
  由於M可能過大,只需求M對5218取模的余數。
輸入格式
  輸入共一行,為一個正整數N。
輸出格式
  輸出共一行,為N的潛能M對5218取模的余數。
樣例輸入
10
樣例輸出
36
數據規模和約定
  1<=N<10^18
 
 為什么要分成3?  正整數分解使得乘積最大問題_小拳頭的博客-CSDN博客_整數拆分乘積最大問題
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
#define MOD 5218
int qpow(int a, ll n)//遞歸實現快速模平方法
{
    if (n == 0)
        return 1;
    else if (n % 2 == 1)
        return qpow(a, n - 1) * a % MOD;
    else
    {
        int temp = qpow(a, n / 2);
        return temp * temp % MOD;
    }
}
int main()
{
    ll n, h, m;
    int result;
    cin >> n;
    h = n / 3;//存有好多個3
    m = n % 3;//余數
    if (m == 1 && h > 0)
    {
        m = 4;
        h = h - 1;
    }
    if (m != 0)
        result = qpow(3, h) * m % MOD;
    else
        result = qpow(3, h);
    cout <<result<< endl;
}
 
 

ALGO-998 娜神平衡

資源限制
時間限制:1.0s   內存限制:256.0MB
問題描述
  娜娜是一個特別可愛的女孩子,作為學神的她最近在情感方面出現了一點點小問題。
  她暗戀的琦琦是一名學霸,他只喜歡長得漂亮和學習很好的女生。
  娜娜學習確實很神,但是她在琦琦面前卻總是表現不出平時的神力。
  琦琦感受到了娜娜對他的愛,但是他還是覺得娜娜的學習並不是特別好,於是他出了一道題給娜娜。
  “娜娜,我們之間的關系需要在不斷深入的同時保持一定的平衡,不可以你總是強勢或者我總是弱勢。”
  琦琦給了娜娜一些兩兩不等的數,希望娜娜能把這些數分成兩組A和B,滿足以下條件:
  1:每一次只能操作一個數,即只取出一個數分入A中或B中;
  2:每一次操作完成后,A中數之和與B中數之和的差不能超過r。
  新時代的丘比特們啊,幫幫娜娜吧!
輸入格式
  輸入共兩行。
  第一行包括兩個正整數n和r,n表示琦琦一共給了n個數,r的意義見題目描述。
  第二行包括n個正整數,分別表示琦琦給的n個數。
輸出格式
  輸出共兩行,分別把A與B兩組數按從小到大輸出。
  注意輸入中n個數的第一個必須分入A組。
  琦琦保證這樣的輸出唯一。
樣例輸入
4 10
9 6 4 20
樣例輸出
4 6 9
20
樣例說明
  先把4和6先后分入A組,再把20分入B組,最后把9分入A組。
數據規模和約定
  很小,真的很小。
 思想: 
  1. 排序數據,便於枚舉判斷
  2. 使用隊列存儲數據,枚舉失敗的數據可以放回隊尾,下次再枚舉
  3. 使用棧存儲枚舉成功的順序,便於回溯(正因為把順序保存了下來,免於用遞歸)
  4. 題目要求第一個數只能放在A中,因此,只要發現B中存在第一個數,就把B當成A就行了(由答案的唯一性,可以知道一個組中的數永遠待在一起,因此只要把存有第一個數的組當成A就可以了,沒必要糾結於優先枚舉進哪個數組)
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
int main()
{
    //sum1存lst1所有元素的和,sum2同理;
    int n, r,sum1=0,sum2=0;
    cin >> n >> r;
    vector<int>lst(n),lst1,lst2,per;
    /*per數組存的元素含義:1表示lst元素存進lst1,
    2表示lst元素存進了lst2;*/
    for (int i = 0; i < lst.size(); i++)
    {
        cin >> lst[i];
    }
    int first = lst[0];//題目要求輸入的第一個數要存進輸出的第一個數組
    sort(lst.begin(), lst.end());//從小到大
    queue<int> q;//建立隊列
    for (int i = 0; i < lst.size(); i++)
    {
        q.push(lst[i]);//進入隊列
    }
    int t=0;
    while (!q.empty())
    {
        t = q.front();
        lst1.push_back(t);//進入lst1;
        sum1 += t;
        per.push_back(1);
        q.pop();
        if ((sum1 - sum2) > r)//如果數進入lst1后,sum1-sum2>10
        {
            lst1.pop_back();//出隊
            per.pop_back();
            sum1 -= t;
            lst2.push_back(t);//入隊
            per.push_back(2);
            sum2 += t;
        }
        if ( sum2 - sum1 > r)//入隊到lst2后,如果還是不滿足條件
        {
            q.push(t);
            lst2.pop_back();//出隊
            sum2 -= t;
            per.pop_back();
            if (per.back() == 1)//如果上一次入隊到lst1;
            {
                per.pop_back();
                int m=lst1.back();//回溯
                lst1.pop_back();
                q.push(m);//再入隊
                sum1 -= m;

            }
            else //如果上一次入隊到lst1;
            {
                per.pop_back();
                int m = lst2.back();
                lst2.pop_back();//回溯
                q.push(m);//再入隊
                sum2 -= m;
            }
        }
    }
    sort(lst1.begin(), lst1.end());//排序
    sort(lst2.begin(), lst2.end());//排序
    for (int i = 0; i < lst2.size(); i++)//判斷first是否再lst2里面
    {
        if (first == lst2[i])
        {
            swap(lst1, lst2);//如果在,則交換數組
            break;
        }
    }
    for (int i = 0; i < lst1.size(); i++)
        cout << lst1[i] << "  ";
    cout << endl;
    for (int i = 0; i < lst2.size(); i++)
        cout << lst2[i] << "  ";
    return 0;
}

參考鏈接:藍橋杯 ALGO-998 娜神平衡(簡單粗暴) - mosqu1to - 博客園 (cnblogs.com)

 

ALGO-997 粘木棍

資源限制
時間限制:1.0s   內存限制:256.0MB
問題描述
  有N根木棍,需要將其粘貼成M個長木棍,使得最長的和最短的的差距最小。
輸入格式
  第一行兩個整數N,M。
  一行N個整數,表示木棍的長度。
輸出格式
  一行一個整數,表示最小的差距
樣例輸入
3 2
10 20 40
樣例輸出
10
數據規模和約定
  N, M<=7
 方法:深度遍歷
#include<iostream>
#include<algorithm>
using namespace std;
int temp, sum[9], flag[9] = { 0 };
/*temp 最大值和最小值的最大差距,
sum[i] 第i組木棍總長度
falg 標准數組,判斷木棍是否被分配到某一組
*/
int lst[9], n, m;
int pos;//遍歷lst數組的當前位置
void DFS(int pos)
{
    if (pos > n)
    {
        int s1 = sum[1],s2 = sum[1];
        for (int i = 1; i <= m; i++)
        {
            s1 = min(s1, sum[i]);
            s2 = max(s2, sum[i]);
        }
        temp = min(s2 - s1, temp);
    }
    for ( int t = pos; t <= n; t++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (flag[t])
                break;
            flag[t] = 1;
            sum[j] += lst[t];
            DFS(pos + 1);
            //回溯
            flag[t] = 0; 
            sum[j] -= lst[t];
        }
    }
}
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> lst[i];
    sort(lst, lst + n+1);//排序的目的只是找出最大值和最小值而已,不排也可
    temp = lst[n] - lst[1];//初始temp的值為lst數組中,最大值-最小值
    DFS(1);
    cout << temp;
    return 0;
}

 

ALGO-996 車的放置

資源限制
時間限制:1.0s   內存限制:256.0MB
問題描述
  在一個n*n的棋盤中,每個格子中至多放置一個車,且要保證任何兩個車都不能相互攻擊,有多少中放法(車與車之間是沒有差別的)
輸入格式
  包含一個正整數n
輸出格式
  一個整數,表示放置車的方法數
樣例輸入
2
樣例輸出
7
數據規模和約定
  n<=8
  【樣例解釋】一個車都不放為1種,放置一個車有4種,放置2個車有2種。
 
什么叫兩個車都不能相互攻擊?就是車兩兩之間,車的行和列不能相同!我之前連題都沒看懂
 
#include<iostream>
using namespace std;
int ans = 1;//輸出結果,好多種方法
int n;
bool flag[10] = { 0 };//標志符號,0表示第i列沒放小車
void DFS(int xx)//深度遍歷
{
    if (xx > n)//遞歸,就一定得有一個跳出遞歸的條件
        return;
    for (int i =1; i <= n; i++)
    {
        if (!flag[i])//如果第i列沒放
        {
            flag[i] = true;
            ans++;//為什么放一輛小車就+1呢?
            //放了一輛小車就改變了這個方陣上一次的狀態,就是一種放法
            DFS(xx + 1);//下一列
            flag[i] = false;//回溯
        }
    }
    DFS(xx + 1);//然后又從第二列、第三列開始放
}
int main() 
{
    cin >> n;
    DFS(1);//從第一列開始放
    cout << ans;
    return 0;

}

ALGO-995 24點

資源限制
時間限制:1.0s   內存限制:256.0MB
問題描述
  24點游戲是一個非常有意思的游戲,很流行,玩法很簡單:給你4張牌,每張牌上有數字(其中A代表1,J代表11,Q代表12,K代表13),你可以利用數學中的加、減、乘、除以及括號想辦法得到24,例如:
  ((A*K)-J)*Q等價於((1*13)-11)*12=24
  加減乘不用多說了,但除法必須滿足能整除才能除!這樣有一些是得不到24點的,所以這里只要求求出不超過24的最大值。
輸入格式
  輸入第一行N(1<=N<=5)表示有N組測試數據。每組測試數據輸入4行,每行一個整數(1到13)表示牌值。
輸出格式
  每組測試數據輸出一個整數,表示所能得到的最大的不超過24的值。
樣例輸入
3
3
3
3
3
1
1
1
1
12
5
13
1
樣例輸出
24
4
21
 


免責聲明!

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



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