第一次接觸算法,只是照着自己的方法學習的,總結寫的可能不是會很好,但我會努力改進。
#STL容器包括順序式容器和關聯式容器。
順序式容器:
·vector:動態數組,從末尾能快速插入與刪除,直接訪問任何元素。
·list:雙鏈表,從任何地方快速插入與刪除。
·deque:雙向隊列,從前面或后面快速插入與刪除,直接訪問任何元素。
·queue:隊列,先進先出
·priority_queue:優先隊列,最高優先級元素總是第一個出列。
·stack:棧,先進后出。
關聯式容器:
·set:集合,快速查找,不允許重復值
·map:一對多映射,基於關鍵字快速查找,不允許重復值
·multimap:一對多映射,基於關鍵字快速查找,允許重復值
1.vector
vector是STL的動態數組,在運行時能根據需要改變數組大小。
vector容器是一個模板類,能存放任何類型的對象。
·定義:
功能 例子 說明
定義int型數組 vector<int>a; 默認初始化,a為空
vector<int>b(a); 用a定義b
vector<int>a(100); a有100個值為0的元素
vector<int>a(100,6); 100個值為6的元素
定義string型數組 vector<string>a(10,"null"); 10個值為null的元素
vector<string>vec(10,"hello"); 10個值為hello的元素
vector<string>b(a.begin(),a.end()); b是a的復制
定義結構型數組 struct point{int x,y;}; a用來存坐標
vector<point>a; 同上
用戶還可以定義多維數組,例如定義一個二維數組:
vector<int>a[MAXN];
它的第一維大小是固定的MAXN,第二位是動態的。用這個方式可以實現圖的鄰接表存儲,細節見:https://oi-wiki.org/lang/csl/sequence-container/
常用操作等等,詳見https://oi-wiki.org/lang/csl/sequence-container/
例子:hdu4841 “圓桌問題” https://vjudge.net/contest/337673#problem
題目大意:類似約瑟夫環問題
解題思路:利用vector容器解題,刪除壞人,留下好人,對於好人輸出G,對於壞人輸出B
代碼:
#include<iostream> #include<vector> #include<cstring> using namespace std; int main(){ vector<int>table; int n,m;//模擬圓桌 while(cin>>n>>m){ table.clear();//清空圓桌 for(int i=0;i<2*n;i++) table.push_back(i);//初始化 int pos=0; //記錄當前位置 for(int i=0;i<n;i++){//趕走n個人 pos=(pos+m-1)%table.size();//圓桌是個環,做取余處理 table.erase(table.begin()+pos);//刪除壞人,讓人數減一 } int j=0; for(int i=0;i<2*n;i++){//打印預先安排座位 if(!(i%50)&&i) cout<<endl; //50字母一行 if(j<table.size()&&i==table[j]){//table留下來的都是好人 j++; cout<<"G"; } else cout<<"B"; } cout<<endl<<endl;//留一個空行 } return 0; }
2.棧和stack
棧:先進后出
棧的有關操作:
stack<Type>s; //定義棧,Type為數據類型,例如int,float,char等
s.push(item); //把item放到棧頂
s.top(); //返回棧頂的元素,但不會刪除
s.pop(); //刪除棧頂的元素,但不會返回.在出棧時需要進行兩步操作,即先top()獲得棧頂元素,再pop()刪除棧頂元素
s.size(); //返回棧中元素的個數
s.empty(); //檢查棧是否為空,如果為空,返回true,否則返回false
爆棧問題:https://blog.csdn.net/weixin_34342905/article/details/93207342
更多詳見:https://oi-wiki.org/ds/stack/
例子:hdu1062”Text Reverse“ https://vjudge.net/contest/337673#problem/B
題目大意:反轉字符串
解題思路:利用棧特性,進行儲存,再輸出。
代碼:
#include<iostream> #include<stack> using namespace std; int main(){ int n; char ch; scanf("%d",&n); getchar(); while(n--){ stack<char>s; while(true){ ch=getchar();//一次讀入一個字符 if(ch==' '||ch=='\n'||ch==EOF){ while(!s.empty()){ printf("%c",s.top()) ;//輸出棧頂 s.pop();//清除棧頂 } if(ch=='\n'||ch==EOF) break; printf(" "); } else s.push(ch);//入棧 } printf("\n"); } return 0; }
例子:hdu1237“簡單計算器” https://vjudge.net/contest/337673#problem/C
題目大意:如上
題目思路:利用棧的操作,中間用2個棧導了一下
代碼:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int a[4],hash1[4],vis[4],hash2[10000]; int flag,temp,cnt; void Show(){ int num = hash1[0] * 1000 + hash1[1] * 100 + hash1[2] * 10 + hash1[3]; if(hash2[num]) return; else{ hash2[num] = 1; if(temp != hash1[0]){ cnt = 0; temp = hash1[0]; flag++; if(flag) printf("\n"); } if(cnt != 0) printf(" "); for(int i = 0;i < 4;i++){ printf("%d",hash1[i]); } cnt++; } return ; } void Dfs(int x){ if(x == 4){ Show(); return ; } for(int i = 0;i < 4;i++){ if(x == 0 && a[i] == 0)continue; if(!vis[i]){ hash1[x] = a[i]; vis[i] = 1; Dfs(x + 1); vis[i] = 0; } } } int main(){ int k = 0; while(~scanf("%d%d%d%d",&a[0],&a[1],&a[2],&a[3])){ if(!a[0] && !a[1] && !a[2] && !a[3]) break; if(k)printf("\n"); sort(a,a+4); memset(hash1,0,sizeof(hash1)); memset(hash2,0,sizeof(hash2)); memset(vis,0,sizeof(vis)); temp = -1,flag = -1,cnt = 0; Dfs(0); printf("\n"); k++; } return 0; }
3.隊列和queue
隊列:先進先出
隊列的有關操作:
queue<Type>q; //定義隊列,Type為數據類型,例如int,float,char等
q.push(item); //把item放進隊列
q.front(); //返回隊首元素,但不會刪除
q.pop(); //刪除隊首元素
q.back(); //返回隊尾元素
q.size(); //返回元素個數
q.empty(); //檢查隊列是否為空
詳情見:https://oi-wiki.org/ds/queue/#_4
例子:hdu1702“acboy needs your help again!” https://vjudge.net/contest/337673#problem/D
題目大意:利用站和隊列的特性,輸出東西
題目思路:定義站和隊列,利用循環結構和判斷條件,將符合要求的數據push進站和隊列,然后按要求輸出
代碼:
#include<iostream> #include<stack> #include<queue> #include<string> using namespace std; int main(){ int t,n,temp; cin>>t; while(t--){ string str,str1; queue<int>Q; stack<int>S; cin>>n>>str; for(int i=0;i<n;i++){ if(str=="FIFO"){ cin>>str1; if(str=="IN"){ cin>>temp; Q.push(temp); } if(str1=="OUT"){ if(Q.empty()) cout<<"None"<<endl; else{ cout<<Q.front()<<endl; Q.pop(); } } } else{ cin>>str1; if(str1=="IN"){ cin>>temp; S.push(temp); } if(str1=="OUT"){ if(S.empty()) cout<<"None"<<endl; else{ cout<<S.top()<<endl; S.pop(); } } } } } return 0; }
優先隊列,顧名思義就是優先級最高的先出隊。
有關操作如下:
q.top(); //返回具有最高優先級的元素值,但不刪除該元素
q.pop(); //刪除最高優先級元素
q,push(item); //插入新元素
可以用優先隊列對數據排序,設定數據小的優先級高,把所有數push進優先隊列后一個個top出來,就得到了從小到大的排序,其總復雜度時O(nlog以2為底的n)
詳見:自己搜索吧,良莠不齊的
例子:hdu1873“看病要排隊” https://vjudge.net/contest/337673#problem/E
題目大意:
解題思路:
代碼:
#include<iostream> #include<stack> #include<queue> #include<string> using namespace std; int main(){ int t,n,temp; cin>>t; while(t--){ string str,str1; queue<int>Q; stack<int>S; cin>>n>>str; for(int i=0;i<n;i++){ if(str=="FIFO"){ cin>>str1; if(str=="IN"){ cin>>temp; Q.push(temp); } if(str1=="OUT"){ if(Q.empty()) cout<<"None"<<endl; else{ cout<<Q.front()<<endl; Q.pop(); } } } else{ cin>>str1; if(str1=="IN"){ cin>>temp; S.push(temp); } if(str1=="OUT"){ if(S.empty()) cout<<"None"<<endl; else{ cout<<S.top()<<endl; S.pop(); } } } } } return 0; }
4.鏈表和list
STL的list是數據結構的雙向鏈表,它的內存空間可以是不連續的,通過指針來進行數據的訪問,它可以高效率的在任意地方刪除和插入,插入和刪除操作是常數時間的。
list和vector的優缺點正好相反,他們的應用場景不同:
(1)vector:插入和刪除操作少,隨機訪問元素頻繁。
(2)list:插入和刪除頻繁,隨機訪問較少。
詳見:https://oi-wiki.org/ds/linked-list/
list例子:hdu1276“士兵隊列訓練問題” https://vjudge.net/contest/337673#problem/F
題目大意:輪流進行1-2,1-3報數,出列
解題思路:構建list,利用循環結構,取余,求人
代碼:
#include <iostream> #include <list> using namespace std; int main(){ int t,n; cin>>t; while(t--){ cin>>n; int k=2; list<int>mylist; list<int>::iterator it; for(int i=1;i<=n;i++) mylist.push_back(i); while(mylist.size()>3){ int num=1; for(it=mylist.begin();it!=mylist.end();){ if(num++%k==0) it=mylist.erase(it); else it++; } k==2?k=3:k=2; } for(it=mylist.begin();it!=mylist.end();it++){ if(it!=mylist.begin()) cout<<" "; cout<<*it; } cout<<endl; } return 0; }
5.set
set和map在競賽題中的應用很廣泛,特別是需要用二叉搜索樹處理數據的題目,如果用set和map實現,能極大地簡化代碼。
set的有關操作:
set<Type>A //定義
A.insert(item); //把item放進set
A.erase(item); //刪除元素item
A.clear(); //清空set
A.empty(); //判斷是否為空
A.size(); //返回元素個數
A.find(k); //返回一個迭代器,指向鍵值K
A.lower_bound(k); //返回一個迭代器,指向鍵值不小於k的第一個元素
A.upper_bound(); //返回一個迭代器,指向鍵值大於k的第一個元素
詳見:https://oi-wiki.org/lang/csl/associative-container/
例子:hdu2094“產生冠軍” https://vjudge.net/contest/337673#problem/G
題目大意:判斷冠軍
題目思路:定義集合A和B,把所有人放進集合A,把所有有失敗記錄的放進集合B,如果A-B=1,則可以判斷存在冠軍,否則不能。
代碼:
#include<iostream> #include<string> #include<set> using namespace std; int main(){ set<string>A,B; string s1,s2; int n; while(cin>>n&&n){ //若輸入為0則退出,若不是0則循環 for(int i=0;i<n;i++){ cin>>s1>>s2; A.insert(s1); A.insert(s2); B.insert(s2); } if(A.size()-B.size()==1) cout<<"Yes"<<endl; else cout<<"No"<<endl; A.clear(); B.clear(); } return 0; }
6.map
map是關聯容器,它實現從鍵(key)到值(value)的映射。map效率高的原因是他用平衡二叉搜索樹來存儲和訪問。
map在例子中具體操作如下:
(1)定義,map<string,int>student,存儲學生的name和id
(2)賦值:例如stduent["Tom"]=15。這里把”Tom“當成普通數組的下標來使用。
(3)查找:在找學號時,可以直接使用student["Tom"]表示他的id,不再去搜索所有的姓名。
詳見:https://oi-wiki.org/lang/csl/associative-container/
例子:hdu2648"Shopping" https://vjudge.net/contest/337673#problem/H
題目大意:得知商店排行
題目思路:如下
代碼:
#include<iostream> #include<map> #include<string> using namespace std; int main(){ int n,m,p; map<string,int>shop; while(cin>>n){ string s; for(int i=1;i<=n;i++) cin>>s;//輸入商店名字,實際上用不着處理 cin>>m; while(m--){ for(int i=1;i<=n;i++){ cin>>p>>s; shop[s]+=p;//用map直接操作商店,加上價格 } int rank=1; map<string,int>::iterator it;//迭代器,,遍歷數據,判斷是否集合中有數據, //有則取出,然后不斷執行 for(it=shop.begin();it!=shop.end();it++) if(it->second>shop["memory"]) rank++; cout<<rank<<endl; } shop.clear(); } return 0; }
7.sort
注意:它排序的范圍是[first,last),包括first,不包括last
<1>sort()的比較函數
sort()可以用自定義的比較函數進行排序,也可以用系統的種函數排序,即less(),greater(),less_equal(),greater_equal()。在默認情況下,程序是按從大到小的順序排序的,less()可以不寫。 例子詳見P34
sort()還可以對結構變量進行排序,例子詳見P35
<2>相關函數
stable_sort():當排序元素相等時,保留原來的順序。在對結構體排序時,當結構體中的排序元素相等時,如果需要保留原序,可以用它。
partial_sort():局部排序。例如有10個數字,求最小的5個數。如果用sort(),需要先全部排序,再輸出前5個;而用它可以直接輸出前5個。
8.next_permutation()
返回值:如果沒有下一個排列組合,返回false,否則返回true。每執行它一次,就會把新的排列放到原來的空間里去。
它的排列范圍時[first,last),包括first,不包括last
例子:hdu1027”Ignatius and the Princess II“ https://vjudge.net/contest/337673#problem/I
題目大意:如題
題目思路:利用它生成一個一個小的序列,直到m小
代碼:
#include<iostream> #include<algorithm> using namespace std; int a[1001]; int main(){ int n,m; while(cin>>n>>m){ for(int i=1;i<=n;i++) a[i]=i;//生成一個字典序最小的序列 int b=1; do{ if(b==m) break; b++; }while(next_permutation(a+1,a+n+1)); for(int i=1;i<n;i++)//注意第一個是a+1,最后一個是a+n cout<<a[i]<<" ";//輸出第m大的字典序 cout<<a[n]<<endl; } return 0; }
例子:hdu"排列2” https://vjudge.net/contest/337673#problem/J
題目大意:如題
題目思路:
代碼:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int a[4],hash1[4],vis[4],hash2[10000]; int flag,temp,cnt; void Show(){ int num = hash1[0] * 1000 + hash1[1] * 100 + hash1[2] * 10 + hash1[3]; if(hash2[num]) return; else{ hash2[num] = 1; if(temp != hash1[0]){ cnt = 0; temp = hash1[0]; flag++; if(flag) printf("\n"); } if(cnt != 0) printf(" "); for(int i = 0;i < 4;i++){ printf("%d",hash1[i]); } cnt++; } return ; } void Dfs(int x){ if(x == 4){ Show(); return ; } for(int i = 0;i < 4;i++){ if(x == 0 && a[i] == 0)continue; if(!vis[i]){ hash1[x] = a[i]; vis[i] = 1; Dfs(x + 1); vis[i] = 0; } } } int main(){ int k = 0; while(~scanf("%d%d%d%d",&a[0],&a[1],&a[2],&a[3])){ if(!a[0] && !a[1] && !a[2] && !a[3]) break; if(k)printf("\n"); sort(a,a+4); memset(hash1,0,sizeof(hash1)); memset(hash2,0,sizeof(hash2)); memset(vis,0,sizeof(vis)); temp = -1,flag = -1,cnt = 0; Dfs(0); printf("\n"); k++; } return 0; }