STL包含:容器,迭代器,空间配置器,配接器,算法,仿函数
1、vector
动态数组,从末尾能快速插入和删除,直接访问任何元素。但是在中间进行插入和删除会造成内存块的复制。如果数组后面的内存空间不够需要重新申请一块足够大的内存。所以时间紧张,所以竞赛的时候就直接用vector吧。
题目 HDU 4841“圆桌问题”
题目分析:可以用vector模拟动态变化的圆桌,赶走n个人下留下的都是好人。但是呢,通过看大佬的博客知道了还有递归可以解决。
代码:递归,公式看代码吧
//递归 old=(new+m-1)%n+1,f(n,m)存活编号与f(n-1,m)
/*1 2 3 ... m-2 m-1 m m+1 m+2 n...
删除m
1 2 3 ... m-2 m-1 m+1 m+2 n...
n-2 n-1 1 2 3 */
#include<bits/stdc++.h>
using namespace std;
const int m=3;
int main(){
int n,f=0;
cin>>n;
for(int i=1;i<=n;i++)
f=(f+m)%i;
cout<<f+1<<endl;
}
牛啊!最强的就是能推出公式来的了直接吊打啊
代码:环形链表
每个人死or活--》bool true/false
期初每个人都是活的 a[]=false
//环形链表
#include<bits/stdc++.h>
using namespace std;
int main()
{
bool a[101]={0};
int n,m,i,f=0,t=0,s=0;
cin>>n>>m;
do{
++t;//枚举所有位置
if(t>n)
t=1;//模拟环状,首尾相连
if(!a[t])
s++;//t上有人就报数
if(s == m){
s=0;//计数器清零
cout<<t<<' ';//输出被杀编号
a[t]=1;//恢复空
f++;//死亡人数+1
}
}while(f!=n);//所有人被杀
return 0;
}
代码:STL
#include<bits/stdc++.h>
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);//赶走坏人,table人数减一
}
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
栈—》先进后出,说一下爆栈问题处理方式:
1、在程序中调大系统的栈,依赖计算机,所以热身的时候一定要试试机子
2、手工写栈(还没学到以后学到再来补充)
题目 HDU 1062“Text Reverse”
代码:
//翻转字符串,栈
#include<bits/stdc++.h>
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;
}
这个题本来我没想到用栈,用的翻转字符串函数,结果WA,这里说一下,翻转字符串函数strrev();反过来是world!hello
3、队列queue
先进先出
题目 HDU 1702 用栈和队列进行模拟
代码:
#include<bits/stdc++.h>
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、优先队列和priority_queue
普通队列是先进先出,有限队列是最高级先出。优先队列不是队列,是堆,底层原理是红黑树,分为大顶堆和小顶堆
题目 HDU 1873 “看病要排队”
代码:
#include<iostream>
#include<functional>
#include<queue>
#include<vector>
using namespace std;
//定义比较结构
struct cmp1{
bool operator ()(int &a,int &b){
return a>b;//最小值优先
}
};
struct cmp2{
bool operator ()(int &a,int &b){
return a<b;//最大值优先
}
};
//自定义数据结构
struct number1{
int x;
bool operator < (const number1 &a) const {
return x>a.x;//最小值优先
}
};
struct number2{
int x;
bool operator < (const number2 &a) const {
return x<a.x;//最大值优先
}
};
int a[]={14,10,56,7,83,22,36,91,3,47,72,0};
number1 num1[]={14,10,56,7,83,22,36,91,3,47,72,0};
number2 num2[]={14,10,56,7,83,22,36,91,3,47,72,0};
int main()
{
priority_queue<int>que;//采用默认优先级构造队列
priority_queue<int,vector<int>,cmp1>que1;//最小值优先
priority_queue<int,vector<int>,cmp2>que2;//最大值优先
priority_queue<int,vector<int>,greater<int> >que3;//注意“>>”会被认为错误,
priority_queue<int,vector<int>,less<int> >que4;最大值优先
priority_queue<number1>que5; //最小优先级队列
priority_queue<number2>que6; //最大优先级队列
int i;
for(i=0;a[i];i++){
que.push(a[i]);
que1.push(a[i]);
que2.push(a[i]);
que3.push(a[i]);
que4.push(a[i]);
}
for(i=0;num1[i].x;i++)
que5.push(num1[i]);
for(i=0;num2[i].x;i++)
que6.push(num2[i]);
printf("采用默认优先关系:/n(priority_queue<int>que;)/n");
printf("Queue 0:/n");
while(!que.empty()){
printf("%3d",que.top());
que.pop();
}
puts("");
puts("");
printf("采用结构体自定义优先级方式一:/n(priority_queue<int,vector<int>,cmp>que;)/n");
printf("Queue 1:/n");
while(!que1.empty()){
printf("%3d",que1.top());
que1.pop();
}
puts("");
printf("Queue 2:/n");
while(!que2.empty()){
printf("%3d",que2.top());
que2.pop();
}
puts("");
puts("");
printf("采用头文件/内定义优先级:/n(priority_queue<int,vector<int>,greater<int>/less<int> >que;)/n");
printf("Queue 3:/n");
while(!que3.empty()){
printf("%3d",que3.top());
que3.pop();
}
puts("");
printf("Queue 4:/n");
while(!que4.empty()){
printf("%3d",que4.top());
que4.pop();
}
puts("");
puts("");
printf("采用结构体自定义优先级方式二:/n(priority_queue<number>que)/n");
printf("Queue 5:/n");
while(!que5.empty()){
printf("%3d",que5.top());
que5.pop();
}
puts("");
printf("Queue 6:/n");
while(!que6.empty()){
printf("%3d",que6.top());
que6.pop();
}
puts("");
return 0;
}
这里有一个优先队列的模板,如下:
#include<iostream>
#include<queue>
#include<string>
using namespace std;
struct Node{
//进行的操作
string str;
//要求哪位医生诊治
int A;
//当前病人的优先级
int B;
//当前病人的编号,或者是说来的时间,因为要满足优先级相同时,根据先来后到诊治。
int time;
};
//自定义优先级。
struct cmp{
bool operator ()(const Node &a,const Node &b)
{
//最大值优先
if(a.B>b.B)
{
return false;
}
//优先级相同时,先来的优先.
else if(a.B==b.B)
{
return a.time>b.time;
}
else{
return true;
}
}
};
int main()
{
int t;
while(cin>>t)
{
Node node;
//定义三个医生相应的优先队列
priority_queue<Node,vector<Node>,cmp> doc1;
priority_queue<Node,vector<Node>,cmp> doc2;
priority_queue<Node,vector<Node>,cmp> doc3;
int time = 0;
while(t--)
{
cin>>node.str;
if(node.str=="IN")
{
cin>>node.A>>node.B;
}
if(node.str=="OUT")
{
cin>>node.A;
}
if(node.str=="IN")
{
//根据A的值,将节点压入不同医生的队列中去
switch (node.A)
{
case 1:{
node.time = ++time;
doc1.push(node);
break;
}
case 2:{
node.time = ++time;
doc2.push(node);
break;
}
case 3:{
node.time = ++time;
doc3.push(node);
break;
}
}
}
//如果是进行看病操作的话,进行出队列操作(恶心,用else不行,必须if判断)
if(node.str=="OUT"){
switch(node.A)
{
case 1:{
if(doc1.empty())
{
cout<<"EMPTY"<<endl;
break;
}
else{
cout<<doc1.top().time<<endl;
doc1.pop();
break;
}
}
case 2:{
if(doc2.empty())
{
cout<<"EMPTY"<<endl;
break;
}
else{
cout<<doc2.top().time<<endl;
doc2.pop();
break;
}
}
case 3:{
if(doc3.empty())
{
cout<<"EMPTY"<<endl;
break;
}
else{
cout<<doc3.top().time<<endl;
doc3.pop();
break;
}
}
}
}
}
}
return 0;
}
凡是优先队列的题,写码写到不想写
5、链表和list
list可以再任意地方删除和插入,和vector优缺点相反,注意list要使用迭代器
题目 HDU 1276“士兵队列训练问题”
代码:
#include<iostream>
#include<list>
using namespace std;
int main(){
int N,x,i;
list<int>a;
list<int>::iterator it;
int k;
scanf("%d",&N);
while(N--){
scanf("%d",&x);
a.clear();
for(i=0;i<x;i++){
a.push_back(i+1);//存储每个士兵的编号,索引加1
}
k=2;//第一次删除2
while(a.size()>3){
i=0;
for(it=a.begin();it!=a.end();){
if((i+1)%k == 0){//删除喊K
it=a.erase(it);
}
else {
it++;
}
i++;
}
if(k==2)k=3;
else k=2;
}
for(it=a.begin();it!=a.end();){
printf("%d",*it);
it++;
if(it!=a.end())printf(" ");
else printf("\n");
}
}
return 0;
}
6、set
集合,底层逻辑是二叉树,特点1、互异性,每个元素只允许出现一次2、不允许两个元素有相同的值3、使用empty()检查set是否为空
题目 HDU 2904“产生冠军”
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
set<string>A,B;//定义集合
string s1,s2;
int n;
while(cin>>n&&n)
{
for(int i=0;i<n;i++){
cin>>s1>>s2;
A.insert(s1); A.insert(s2);//把所有数据放入集合A
B.insert(s2);
}
if(A.size()-B.size()==1)
cout<<"yes"<<endl;
else
cout<<"no"<<endl;
A.clear();B.clear();
}
return 0;
}
7、map
映射,也需要使用迭代器
题目 HDU 2648“shopping”
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m,p;
map<string,int>shop;//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;//s作为数组下标
}
int rank=1;
//定义迭代器
map<string,int>::iterator it;
for(it=shop.begin();it!=shop.end();it++)
if(it->second>shop["memony"])rank++;
cout<<rank<<endl;
}
shop.clear();
}
return 0;
}
8、sort
很常用,注意他的范围是[)包括first不包括last,在默认情况下是按照从小到大大顺序排列的
先留着,以后再来补充题目
9、next_permutation
求排列组合的函数,注意他的范围和sort一样,并且一定是一个字典的最小序列
题目 HDU 1027
代码: