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的正整數。
以下n行描述該方格。金幣數保證是不超過1000的正整數。
輸出格式
最多能拿金幣數量。
樣例輸入
3
1 3 3
2 2 2
3 1 2
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的一個排列。若有多種答案,則輸出字典序最小的那一個。數據保證有解。
例如:
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
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找到了聰明的你,問他最多可以帶走多少個石子。
在走出了怪物森林以后,JiaoShou看到了排成一排的N個石子。
這些石子很漂亮,JiaoShou決定以此為禮物。
但是這N個石子被施加了一種特殊的魔法。
如果要取走石子,必須按照以下的規則去取。
每次必須取連續的2*K個石子,並且滿足前K個石子的重量和小於等於S,后K個石子的重量和小於等於S。
由於時間緊迫,Jiaoshou只能取一次。
現在JiaoShou找到了聰明的你,問他最多可以帶走多少個石子。
輸入格式
第一行兩個整數N、S。
第二行N個整數,用空格隔開,表示每個石子的重量。
第二行N個整數,用空格隔開,表示每個石子的重量。
輸出格式
第一行輸出一個數表示JiaoShou最多能取走多少個石子。
樣列輸入
8 3
1 1 1 1 1 1 1 1
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,且非負
對於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問你還想吃糖果么?(嘿嘿嘿)說着眼角路出奇怪的微笑...
kAc說你只能拿m次糖果,聰明的你當然想要拿最多的糖果來吃啦啦啦~
//第二天,kAc問你還想吃糖果么?(嘿嘿嘿)說着眼角路出奇怪的微笑...
輸入格式
第一行兩個數字n和m,第二行有n個數字A[i]。
輸出格式
輸出一行表示最多能拿幾個糖果。
樣例輸入
2 2
1 2
1 2
樣例輸出
3
數據規模和約定
0<n≤1000
其余數字都是不超過1,000,000,000的非負整數。
其余數字都是不超過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,求它的潛能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。
新時代的丘比特們啊,幫幫娜娜吧!
她暗戀的琦琦是一名學霸,他只喜歡長得漂亮和學習很好的女生。
娜娜學習確實很神,但是她在琦琦面前卻總是表現不出平時的神力。
琦琦感受到了娜娜對他的愛,但是他還是覺得娜娜的學習並不是特別好,於是他出了一道題給娜娜。
“娜娜,我們之間的關系需要在不斷深入的同時保持一定的平衡,不可以你總是強勢或者我總是弱勢。”
琦琦給了娜娜一些兩兩不等的數,希望娜娜能把這些數分成兩組A和B,滿足以下條件:
1:每一次只能操作一個數,即只取出一個數分入A中或B中;
2:每一次操作完成后,A中數之和與B中數之和的差不能超過r。
新時代的丘比特們啊,幫幫娜娜吧!
輸入格式
輸入共兩行。
第一行包括兩個正整數n和r,n表示琦琦一共給了n個數,r的意義見題目描述。
第二行包括n個正整數,分別表示琦琦給的n個數。
第一行包括兩個正整數n和r,n表示琦琦一共給了n個數,r的意義見題目描述。
第二行包括n個正整數,分別表示琦琦給的n個數。
輸出格式
輸出共兩行,分別把A與B兩組數按從小到大輸出。
注意輸入中n個數的第一個必須分入A組。
琦琦保證這樣的輸出唯一。
注意輸入中n個數的第一個必須分入A組。
琦琦保證這樣的輸出唯一。
樣例輸入
4 10
9 6 4 20
9 6 4 20
樣例輸出
4 6 9
20
20
樣例說明
先把4和6先后分入A組,再把20分入B組,最后把9分入A組。
數據規模和約定
很小,真的很小。
思想:
- 排序數據,便於枚舉判斷
- 使用隊列存儲數據,枚舉失敗的數據可以放回隊尾,下次再枚舉
- 使用棧存儲枚舉成功的順序,便於回溯(正因為把順序保存了下來,免於用遞歸)
- 題目要求第一個數只能放在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-997 粘木棍
資源限制
時間限制:1.0s 內存限制:256.0MB
問題描述
有N根木棍,需要將其粘貼成M個長木棍,使得最長的和最短的的差距最小。
輸入格式
第一行兩個整數N,M。
一行N個整數,表示木棍的長度。
一行N個整數,表示木棍的長度。
輸出格式
一行一個整數,表示最小的差距
樣例輸入
3 2
10 20 40
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種。
【樣例解釋】一個車都不放為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的最大值。
((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
3
3
3
3
1
1
1
1
12
5
13
1
樣例輸出
24
4
21
4
21