#include<bits/stdc++.h>#definexfirst#defineysecondusingnamespace std;typedef pair<int,int> PII;constint N =55, M = N * N;int n, m;int g[N][N];
PII q[M];bool st[N][N];intbfs(int sx,int sy){int dx[]={0,-1,0,1}, dy[]={-1,0,1,0};int hh =0, tt =0;int area =0;q[0]={sx, sy};st[sx][sy]=1;while(hh <= tt){PII t = q[hh ++];area ++;for(int i =0; i <4; i ++){int a = t.x + dx[i], b = t.y + dy[i];if(a <0|| a >= n || b <0|| b >= m)continue;if(st[a][b])continue;// if (g[a][b] >> i & 1) continue; 是t.x而非a//1 2 4 8 -> 二進制中0 1 2 3位上是否為1if(g[t.x][t.y]>> i &1)continue;//二進制中第i位是否為1,若為1則返回1st[a][b]=1;// area ++ ; //不然的話main函數中。。。 整個area會少1q[++ tt]={a, b};}}return area;}intmain(){cin >> n >> m;for(int i =0; i < n; i ++)for(int j =0; j < m; j ++)cin >> g[i][j];int cnt =0, area =0;for(int i =0; i < n; i ++)for(int j =0; j < m; j ++){if(!st[i][j]){cnt ++;area =max(area,bfs(i, j));}}cout << cnt << endl;cout << area << endl;return0;}
S 的所有格子都有相同的高度。 S 的所有格子都連通。 對于 s 屬于 S,與 s 相鄰的 s′ 不屬于 S,都有 ws>ws′(山峰),或者 ws<ws′(山谷)。 如果周圍不存在相鄰區域,則同時將其視為山峰和山谷。 你的任務是,對于給定的地圖,求出山峰和山谷的數量,如果所有格子都有相同的高度,那么整個地圖即是山峰,又是山谷。
#include<bits/stdc++.h>#definexfirst#defineysecondusingnamespace std;typedef pair<int,int> PII;constint N =1010, M = N * N;int n;int g[N][N];
PII q[M];
PII pre[N][N];voidbfs(int sx,int sy){memset(pre,-1,sizeof(pre));//初始化pre數組,定義一個不能到達的值為未訪問int dx[]={1,0,-1,0}, dy[]={0,1,0,-1};int hh =0, tt =0;q[0]={sx, sy};pre[sx][sy]={0,0};while(hh <= tt){PII t = q[hh ++];for(int i =0; i <4; i ++){int a = t.x + dx[i], b = t.y + dy[i];if(a <0|| a >= n || b <0|| b >= n)continue;if(g[a][b])continue;if(pre[a][b].x !=-1)continue;//不能寫pre[a][b] != -1q[++ tt]={a, b};pre[a][b]= t;}}}intmain(){cin >> n;for(int i =0; i < n; i ++)for(int j =0; j < n; j ++)scanf("%d",&g[i][j]);bfs(n -1, n -1);//從終點開始遍歷,為了prePII end ={0,0};//定義一個pair類型變量end方便遍歷pre數組while(1){printf("%d %d\n", end.x, end.y);if(end.x == n -1&& end.y == n -1)break;end = pre[end.x][end.y];}return0;}
#include<bits/stdc++.h>#defineendl'\n'#definexfirst#defineysecondusingnamespace std;typedef pair<int,int> PII;constint N =155, M = N * N;int n, m;char g[N][N];int dist[N][N];
PII q[M];intbfs(){memset(dist,-1,sizeof(dist));int dx[]={-2,-1,1,2,2,1,-1,-2}, dy[]={1,2,2,1,-1,-2,-2,-1};int sx, sy;for(int i =0; i < n; i ++)for(int j =0; j < m; j ++)if(g[i][j]=='K')sx = i, sy = j;int hh =0, tt =0;q[0]={sx, sy};dist[sx][sy]=0;while(hh <= tt){PII t = q[hh ++];for(int i =0; i <8; i ++){int a = t.x + dx[i], b = t.y + dy[i];if(a <0|| a >= n || b <0|| b >= m)continue;if(g[a][b]=='*')continue;if(dist[a][b]!=-1)continue;if(g[a][b]=='H')return dist[t.x][t.y]+1;dist[a][b]= dist[t.x][t.y]+1;q[++ tt]={a, b};}}return-1;}intmain(){// cin >> n >> m;cin >> m >> n;for(int i =0; i < n; i ++) cin >> g[i];cout <<bfs()<< endl;}
抓住那頭牛 題目 提交記錄 討論 題解 視頻講解
農夫知道一頭牛的位置,想要抓住它。
農夫和牛都位于數軸上,農夫起始位于點 N,牛位于點 K。
農夫有兩種移動方式:
從 X 移動到 X?1 或 X+1,每次移動花費一分鐘 從 X 移動到 2?X,每次移動花費一分鐘 假設牛沒有意識到農夫的行動,站在原地不動。
農夫最少要花多少時間才能抓住牛?
輸入格式 共一行,包含兩個整數N和K。
輸出格式 輸出一個整數,表示抓到牛所花費的最少時間。
數據范圍 0≤N,K≤105 輸入樣例: 5 17 輸出樣例: 4
//所有邊的權重相同都為1,就可以用bfs求出最短路徑#include<cstring>#include<iostream>#include<algorithm>usingnamespace std;constint N =1e5+10;//范圍 waint n, k;int q[N];int dist[N];intbfs(){memset(dist,-1,sizeof dist);dist[n]=0;q[0]= n;int hh =0, tt =0;while(hh <= tt){int t = q[hh ++];if(t == k)return dist[k];if(t +1< N && dist[t +1]==-1){dist[t +1]= dist[t]+1;q[++ tt]= t +1;}if(t -1>=0&& dist[t -1]==-1){dist[t -1]= dist[t]+1;q[++ tt]= t -1;}if(t *2< N && dist[t *2]==-1){dist[t *2]= dist[t]+1;q[++ tt]= t *2;}}return-1;}intmain(){cin >> n >> k;cout <<bfs()<< endl;return0;}
矩陣距離 題目 提交記錄 討論 題解 視頻講解
給定一個 N 行 M 列的 01 矩陣 A,A[i][j] 與 A[k][l] 之間的曼哈頓距離定義為:
dist(A[i][j],A[k][l])=|i?k|+|j?l| 輸出一個 N 行 M 列的整數矩陣 B,其中:
//樸素想法:有一個起點的時候。。。 有多個起點:把每個1分別放在隊首,遍歷一遍,保留最小值,O(n^2),鐵T//圖論中求一個點到其他最近的點的最短距離,與多源最短路(任意兩點最短距離)不一樣,可以轉換為單源最短路//多源 1.兩端性 2.單調性 e.g x x x x x ... x+1 x+1 x+1 ...//本題輸入的時候是一串連在一起的數字,中間沒有空格相隔,所以要用字符串讀,不能用int//1e3 * 1e3 的 char 類型輸入 -> 1e6的字節 只占1MB空間,不算大#include<bits/stdc++.h>#defineend'\n'#definexfirst#defineysecondusingnamespace std;typedef pair<int,int> PII;constint N =1010, M = N * N;int n, m;char g[N][N];
PII q[M];int dist[N][N];voidbfs(){memset(dist,-1,sizeof(dist));int dx[]={1,0,-1,0}, dy[]={0,1,0,-1};int hh =0, tt =-1;// wa!!!for(int i =1; i <= n; i ++)for(int j =1; j <= m; j ++)if(g[i][j]=='1'){dist[i][j]=0;q[++ tt]={i, j};}while(hh <= tt){PII t = q[hh ++];for(int i =0; i <4; i ++){int a = t.x + dx[i], b = t.y + dy[i];if(a <=0|| a > n || b <=0|| b > m)continue;if(dist[a][b]!=-1)continue;dist[a][b]= dist[t.x][t.y]+1;q[++ tt]={a, b};}}}intmain(){cin >> n >> m;for(int i =1; i <= n; i ++)scanf("%s", g[i]+1);bfs();for(int i =1; i <= n; i ++){for(int j =1; j <= m; j ++){printf("%d ", dist[i][j]);// %d而非%c wa}puts("");}return0;}
//相當于給了一個無向圖,這個無向圖中只有兩種邊,第一種邊邊權是0,第二種邊權是1(前面是所有邊邊權都是1,可以直接BFS求它最短路),且僅包含01邊權//問在這樣的圖上,從起點到終點的最短路徑是多少 ,可以用dijkstra做(dijk要求其實是在非負權值圖上做)//因為沿斜線走的,一開始橫縱坐標之和是偶數,所以之后也都是偶數,所以是之和是奇數的點一定到不了//把邊權為0的拓展到隊首,邊權為1的拓展到隊尾,仍滿足兩段性和單調性 x x .. x || x x .. x || x+1 x+1 .. x+1 || x+2 x+2 .. x+2 //每個點可能會被更新入隊多次(di=dj, di+1>dj+0),和一般bfs(d<=d_ -> d+1 <= d_+1,前面更新的肯定小于等于后面更新的,所以每個點只會入隊一次)不一樣,本質上dijk//每個點第一次被拓展到時不一定是最優解,只有這個點第一次從堆中出來的時候,也就是當前點是當前堆中最小值時,它的值才一定是最優解,這就是一個簡化版的dijk#include<bits/stdc++.h>usingnamespace std;typedef pair<int,int> PII;constint N =550, M = N * N;int n, m;char g[N][N];int dist[N][N];bool st[N][N];intbfs(){deque<PII> q;memset(st,0,sizeof(st));memset(dist,0x3f,sizeof(dist));//dist初始化不再是-1,因為需要更新最小值char cs[5]="\\/\\/";// 轉義字符 4 -> 5 注意順序是順時針(和下面dx, ix都是對應的)數過來那個點周圍的四個方格的int dx[]={-1,-1,1,1}, dy[]={-1,1,1,-1};int ix[]={-1,-1,0,0}, iy[]={-1,0,0,-1};q.push_back({0,0});dist[0][0]=0;while(q.size()){auto t = q.front();q.pop_front();int x = t.first, y = t.second;if(x == n && y == m)return dist[n][m];if(st[x][y])continue;st[x][y]=1;for(int i =0; i <4; i ++){int a = x + dx[i], b = y + dy[i];if(a <0|| a > n || b <0|| b > m)continue;//輸入進的是方格個數,而格點是[0,n]int ga = x + ix[i], gb = y + iy[i];int w =(g[ga][gb]!= cs[i]);int d = dist[x][y]+ w;if(d <= dist[a][b]){dist[a][b]= d;if(!w) q.push_front({a, b});else q.push_back({a, b});}}}return-1;}intmain(){int T;scanf("%d",&T);while(T--){scanf("%d %d",&n,&m);for(int i =0; i < n; i ++)scanf("%s", g[i]);//和下一條的先后順序,即使一開始就判斷出答案,也要先輸入if(n + m &1)puts("NO SOLUTION");elseprintf("%d\n",bfs());}return0;}
字串變換 題目 提交記錄 討論 題解 視頻講解
已知有兩個字串 A, B 及一組字串變換的規則(至多 6 個規則):
A1→B1 A2→B2 …
規則的含義為:在 A 中的子串 A1 可以變換為 B1、A2 可以變換為 B2…。
例如:A=abcd B=xyz
變換規則為:
abc → xu ud → y y → yz
則此時,A 可以經過一系列的變換變為 B,其變換的過程為:
abcd → xud → xy → xyz
共進行了三次變換,使得 A 變換為 B。
輸入格式 輸入格式如下:
A B A1 B1 A2 B2 … …
第一行是兩個給定的字符串 A 和 B。
接下來若干行,每行描述一組字串變換的規則。
所有字符串長度的上限為 20。
輸出格式 若在 10 步(包含 10 步)以內能將 A 變換為 B ,則輸出最少的變換步數;否則輸出 NO ANSWER!。
輸入樣例: abcd xyz abc xu ud y y yz 輸出樣例: 3
//即使只有6種規則,一次op分支是很多的,復雜度很高,所以要a和b相互找對方//復雜度 e.g k^10 -> 2*k^5 指數級變化 搜索需要的狀態量面積變為原先的比如2/k^5//搜索寬度太寬時(單向超時時)用雙向//雙向bfs搜時, 兩邊每次擴展的時候必須把一整層擴展出來,否則wa,不能每次只擴展一個點#include<bits/stdc++.h>usingnamespace std;constint N =10;string A, B;int n;
string a[N], b[N];intextend(queue<string>& q, unordered_map<string,int>& da, unordered_map<string,int>& db, string a[N], string b[N]){int d = da[q.front()];//一次拓展一層while(q.size()&& da[q.front()]== d){auto t = q.front();q.pop();for(int i =0; i < n; i ++)for(int j =0; j <(int)t.size(); j ++){if(t.substr(j, a[i].size())== a[i]){string r = t.substr(0, j)+ b[i]+ t.substr(j + a[i].size());//substr只傳一個參數表示從這個位置到末尾的子串if(db.count(r))return da[t]+1+ db[r];if(da.count(r))continue;da[r]= da[t]+1;q.push(r);}}}return11;}intbfs(){queue<string> qa, qb;unordered_map<string,int> da, db;da[A]=0, db[B]=0;qa.push(A), qb.push(B);int step =0;while(qa.size()&& qb.size()){int t;//用小的那個拓展if(qa.size()<= qb.size()) t =extend(qa, da, db, a, b);else t =extend(qb, db, da, b, a);if(t <=10)return t;if(++ step ==11)return-1;}return-1;}intmain(){cin >> A >> B;while(cin >> a[n]>> b[n]) n ++;int t =bfs();if(t ==-1)puts("NO ANSWER!");elseprintf("%d\n", t);return0;}//2.2.1 DFS中的連通性和搜索順序//有些問題既可以深搜做也可以寬搜 基于連通性的模型的問題 比如flood-fill模型,或有關于圖和樹的遍歷///它們都有個特點,判斷從一個點能否走到某個點,是在棋盤內部做的,包括樹的遍歷也是,,是一個局部信息//dfs的另一類題一般都是看成一個整體,問能否從這一個整體變成另一個整體,是把一個整體看出一個點,
//flood-fill 用bfs或dfs均可,只是dfs有爆棧的風險 1M -> 256M#include<bits/stdc++.h>#defineendl'\n'#definexfirst#defineysecondusingnamespace std;typedeflonglong ll;typedef pair<int,int> PII;constint maxn =25;int n, m;char g[maxn][maxn];int res =0;int dx[]={1,0,-1,0}, dy[]={0,1,0,-1};voidbfs(int x,int y){queue<PII> q;q.push({x, y});while(q.size()){auto t = q.front();q.pop();res ++;for(int i =0; i <4;++ i){int a = t.x + dx[i], b = t.y + dy[i];if(a <0|| a >= n || b <0|| b >= m)continue;if(g[a][b]!='.')continue;g[a][b]='#';q.push({a, b});}}}intmain(){while(cin >> m >> n, n || m){for(int i =0; i < n;++ i) cin >> g[i];res =0;int x, y;for(int i =0; i < n;++ i)for(int j =0; j < m;++ j){if(g[i][j]=='@')x = i, y = j;}bfs(x, y);cout << res << endl;}return0;}#include<bits/stdc++.h>#defineendl'\n'usingnamespace std;typedeflonglong ll;constint maxn =25;int n, m;char g[maxn][maxn];int dx[]={1,0,-1,0}, dy[]={0,1,0,-1};intdfs(int x,int y){int res =1;g[x][y]='#';for(int i =0; i <4; i ++){int a = x + dx[i], b = y + dy[i];if(a <0|| a >= n || b <0|| b >= m)continue;if(g[a][b]!='.')continue;res +=dfs(a, b);}return res;}intmain(){while(cin >> m >> n, n || m){for(int i =0; i < n;++ i) cin >> g[i];int x, y;for(int i =0; i < n;++ i)for(int j =0; j < m;++ j)if(g[i][j]=='@')x = i, y = j;cout <<dfs(x, y)<< endl;}return0;}//后面的外部搜索//求最值,求數量 和dp問題一樣,但爆搜比較簡單,dp一個集合
//搜索樹//這題是,搜索樹中,每個狀態都是一個節點,每變化一步,都變一下變一下,它每個兒子都是把父節點復制過去變一下//恢復現場 下去是什么樣回來就是什么樣 所以這里不需要st初始化,因為回來的時候和下去時候一樣全是0//一般不會去問dfs的時間復雜度,一般認為是指數的,,除非是內部搜索,每個點只搜一次,所以是線性的//這是個外部搜索 所以需要恢復現場(相當于是否需要回溯?//將st變為0或1,放外面而不放for內部的話,可以減少運算,快一點//搜索結束就是把點搜完 所以再傳一個參數,當前在搜第幾個點#include<bits/stdc++.h>#defineendl'\n'usingnamespace std;typedeflonglong ll;constint N =15;int n, m;bool st[N][N];int ans;int dx[8]={-2,-1,1,2,2,1,-1,-2}, dy[8]={1,2,2,1,-1,-2,-2,-1};voiddfs(int x,int y,int cnt){if(cnt == n * m){ans ++;return;}st[x][y]=1;for(int i =0; i <8; i ++){int a = x + dx[i], b = y + dy[i];if(a <0|| a >= n || b <0|| b >= m)continue;if(st[a][b])continue;dfs(a, b, cnt +1);}st[x][y]=0;}intmain(){int T;cin >> T;while(T--){int x, y;cin >> n >> m >> x >> y;ans =0;dfs(x, y,1);cout << ans << endl;}return0;}#include<bits/stdc++.h>#defineendl'\n'usingnamespace std;typedeflonglong ll;constint N =15;int n, m;bool st[N][N];int ans, cnt;int dx[8]={-2,-1,1,2,2,1,-1,-2}, dy[8]={1,2,2,1,-1,-2,-2,-1};voiddfs(int x,int y){if(cnt == n * m){ans ++;return;}st[x][y]=1;cnt ++;for(int i =0; i <8; i ++){int a = x + dx[i], b = y + dy[i];if(a <0|| a >= n || b <0|| b >= m)continue;if(st[a][b])continue;dfs(a, b);}st[x][y]=0;cnt --;}intmain(){int T;cin >> T;while(T--){int x, y;cin >> n >> m >> x >> y;ans =0;cnt =1;dfs(x, y);cout << ans << endl;}return0;}#include<bits/stdc++.h>usingnamespace std;constint N =15;int n, m, ans;bool st[N][N];int dx[]={-2,-1,1,2,2,1,-1,-2}, dy[]={1,2,2,1,-1,-2,-2,-1};voiddfs(int x,int y,int cnt){// st[x][y] = 1; 都可以if(cnt == n * m){ans ++;// return ; 這里不能return不然的話就沒辦法恢復狀態了}st[x][y]=1;for(int i =0; i <8; i ++){int a = x + dx[i], b = y + dy[i];if(a <0|| a >= n || b <0|| b >= m)continue;if(st[a][b])continue;dfs(a, b, cnt +1);}st[x][y]=0;}intmain(){int T;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);int x, y;scanf("%d%d",&x,&y);ans =0;dfs(x, y,1);cout << ans << endl;}return0;}
我們可以任意選擇重合部分的長度,但其長度必須大于等于1,且嚴格小于兩個串的長度,例如 at 和 atide 間不能相連。
輸入格式 輸入的第一行為一個單獨的整數 n 表示單詞數,以下 n 行每行有一個單詞(只含有大寫或小寫字母,長度不超過20),輸入的最后一行為一個單個字符,表示“龍”開頭的字母。
你可以假定以此字母開頭的“龍”一定存在。
輸出格式 只需輸出以此字母開頭的最長的“龍”的長度。
數據范圍 n≤20 輸入樣例: 5 at touch cheat choose tact a 輸出樣例: 23 提示 連成的“龍”為 atoucheatactactouchoose。
//表述“每個單詞最多被使用兩次“和”每個單詞最多在龍中出現兩次“的區別,包含,一個單詞在另一個單詞中出現,kmp算法#include<bits/stdc++.h>#defineendl'\n'usingnamespace std;typedeflonglong ll;constint N =25;string word[N];int g[N][N];int used[N];int ans, n;voiddfs(string dragon,int last){ans =max(ans,(int)dragon.size());//max函數里兩個參數必須同一類型used[last]++;//雖說last,其實是當前字符串的下標for(int i =0; i < n; i ++)if(g[last][i]&& used[i]<2)//與重合長度有關來推公式dfs(dragon + word[i].substr(g[last][i]), i);//substr只傳一個參數表示從這個位置開始到末尾的子串,用來求后綴used[last]--;}intmain(){cin >> n;char start;for(int i =0; i < n; i ++) cin >> word[i];cin >> start;for(int i =0; i < n; i ++)for(int j =0; j < n; j ++){string a = word[i], b = word[j];for(int k =1; k <min(a.size(), b.size()); k ++)//因為重合的越少dragon越長,所以k從1個開始if(a.substr(a.size()- k, k)== b.substr(0, k))//后綴等于前綴{g[i][j]= k;break;//找到最小的就好}}for(int i =0; i < n; i ++)if(word[i][0]== start)dfs(word[i], i);cout << ans << endl;return0;}
分成互質組 題目 提交記錄 討論 題解 視頻講解
給定 n 個正整數,將它們分組,使得每組中任意兩個數互質。
至少要分成多少個組?
輸入格式 第一行是一個正整數 n。
第二行是 n 個不大于10000的正整數。
輸出格式 一個正整數,即最少需要的組數。
數據范圍 1≤n≤10 輸入樣例: 6 14 20 33 117 143 175 輸出樣例: 3
//可以轉化成圖論問題,如果兩1118. 分成互質組//如果是組合問題就不要做成排列問題了#include<bits/stdc++.h>#defineendl'\n'usingnamespace std;typedeflonglong ll;int n, len;int ans;int a[10];
vector<int>g[10];intinlinegcd(int a,int b){return b ?gcd(b, a % b): a;}boolinlinecheck(int v,int u){for(int i =0; i < g[v].size(); i ++)if(gcd(g[v][i], u)>1)return0;return1;}voiddfs(int u){if(u == n){ans =min(ans, len);return;}for(int i =0; i < len; i ++)if(check(i, a[u])){g[i].push_back(a[u]);dfs(u +1);g[i].pop_back();}g[len ++].push_back(a[u]);dfs(u +1);g[-- len].pop_back();}intmain(){scanf("%d",&n);for(int i =0; i < n; i ++)scanf("%d", a + i);ans = n;dfs(0);printf("%d\n", ans);}#include<bits/stdc++.h>usingnamespace std;constint N =15;int a[N];int n, ans = N;bool st[N];int group[N][N];intinlinegcd(int a,int b){return b ?gcd(b, a % b): a;}boolinlinecheck(int g,int gc,int i){for(int j =0; j < gc; j ++){if(gcd(a[group[g][j]], a[i])!=1)returnfalse;}returntrue;}voiddfs(int g,int gc,int tc,int start){if(g >= ans)return;if(tc == n){ans =min(ans, g);return;}bool flag =1;for(int i = start; i < n; i ++){if(!st[i]&&check(g, gc, i)){st[i]=1;group[g][gc]= i;dfs(g, gc +1, tc +1, i +1);st[i]=0;flag =0;}}if(flag)dfs(g +1,0, tc,0);}intmain(){cin >> n;for(int i =0; i < n; i ++)scanf("%d", a + i);dfs(1,0,0,0);cout << ans << endl;return0;}//2.2.2 DFS之剪枝//1.優化搜索順序//2.排除等效冗余//3.可行性剪枝//4.最優性剪枝//5.記憶化搜索(DP)
小貓爬山 題目 提交記錄 討論 題解 視頻講解
翰翰和達達飼養了 N 只小貓,這天,小貓們要去爬山。
經歷了千辛萬苦,小貓們終于爬上了山頂,但是疲倦的它們再也不想徒步走下山了(嗚咕>_<)。
翰翰和達達只好花錢讓它們坐索道下山。
索道上的纜車最大承重量為 W,而 N 只小貓的重量分別是 C1、C2……CN。
當然,每輛纜車上的小貓的重量之和不能超過 W。
每租用一輛纜車,翰翰和達達就要付 1 美元,所以他們想知道,最少需要付多少美元才能把這 N 只小貓都運送下山?
#include<bits/stdc++.h>usingnamespace std;typedeflonglong ll;constint N =20;ll n, w, ans = N;
vector<ll>g;
ll cat[N];voiddfs(int u){if(g.size()>= ans)return;if(u == n){ans =min(ans,(ll)g.size());return;}for(int i =0; i < g.size(); i ++){if(g[i]+ cat[u]<= w){g[i]+= cat[u];dfs(u +1);g[i]-= cat[u];}}g.push_back(cat[u]);dfs(u +1);g.pop_back();}intmain(){cin >> n >> w;for(int i =0; i < n; i ++)scanf("%d", cat + i);dfs(0);cout << ans << endl;return0;}#include<bits/stdc++.h>usingnamespace std;constint N =20;int n, w;int cat[N];int ans = N;int sum[N];voiddfs(int u,int k){if(k >= ans)return;//最優性剪枝if(u == n){ans = k;return;}for(int i =0; i < k; i ++){if(sum[i]+ cat[u]<= w)//可行性剪枝{sum[i]+= cat[u];dfs(u +1, k);sum[i]-= cat[u];}}sum[k]= cat[u];//[0, k - 1],所以sum[k]是新開的dfs(u +1, k +1);sum[k]-= cat[u];}intmain(){cin >> n >> w;for(int i =0; i < n; i ++)scanf("%d", cat + i);//優化搜索順序sort(cat, cat + n);reverse(cat, cat + n);dfs(0,0);cout << ans << endl;return0;}