======面向对象与STL======
人生苦短,我要面向对象。
Warning:找不到对象
STL容器的真正含义:啊!是大佬(方言ShiTaLao)!我死了
同理,数据库语言SQL的真实含义:啊!是巨佬(方言ShiQuLao)!我死了
=====vector=====
最简单的STL是vector,简单到不能再简单了。
其中vector的insert功能很好地模拟了链表的插入操作,虽然vector的本质是数组。
(但是写一个数组的插入岂不是很繁?人生苦短啊)
例如:
OJ编号263:jhljx又来了。
#include
#include
#include
#include
using namespace std;
char sorted;
char Add[4]="Add";
char Del[4]="Del";
char Sum[4]="Sum";
char op[5];
int tmpint;
int n;
long long result;
int main()
{
while(~scanf("%d",&n))
{
vector a;
sorted=1;
while(n--)
{
scanf("%s",op);
if(!strcmp(op,Add))
{
scanf("%d",&tmpint);
a.push_back(tmpint);
sorted=0;
}
else if(!strcmp(op,Del))
{
if(!sorted)
{
sort(a.begin(),a.end());
sorted=1;
}
scanf("%d",&tmpint);
vector::iterator it;
for(it=a.begin();it!=a.end();++it)
{
if(*it==tmpint)
{
a.erase(it);
break;
}
}
}
else if(!strcmp(op,Sum))
{
result=0;
if(!sorted)
{
sort(a.begin(),a.end());
sorted=1;
}
int i;
for(i=2;i
OJ编号266:AZY学习顺序表。
#include
#include
#include
using namespace std;
int n,m;
int tmpint;
char Insert[5]="Ins";
char Delete[5]="Del";
char Locate[5]="Loc";
char Getcha[5]="Get";
char operation[5];
int opA,opB;
int main()
{
while(~scanf("%d%d",&n,&m))
{
vector a;
int i;
for(i=0;i(a.size()+1)||opA<=0)
{
printf("Wrong input!\n");
}
else
{
a.insert(a.begin()+opA-1,opB);
vector::iterator ni;
for(ni=a.begin();ni!=a.end();ni++)
{
printf("%d ",*ni);
}
printf("\n");
}
}
else if(!strcmp(operation,Delete))
{
scanf("%d",&opA);
char mark=0;
vector::iterator it;
for(it=a.begin();it!=a.end();++it)
{
if(*it==opA)
{
mark=1;
a.erase(it);
vector::iterator ni;
for(ni=a.begin();ni!=a.end();ni++)
{
printf("%d ",*ni);
}
printf("\n");
break;
}
}
if(!mark)
{
printf("Wrong input!\n");
}
}
else if(!strcmp(operation,Locate))
{
scanf("%d",&opA);
char mark=0;
vector::iterator it=a.begin();
for(i=0;it+i!=a.end();++i)
{
if(*(it+i)==opA)
{
mark=1;
printf("%d\n",++i);
break;
}
}
if(!mark)
{
printf("Wrong input!\n");
}
}
else if(!strcmp(operation,Getcha))
{
scanf("%d",&opA);
vector::iterator it=a.begin();
if(opA>a.size()||opA<=0)
{
printf("Wrong input!\n");
}
else
{
printf("%d\n",*(it+opA-1));
}
}
}
}
}
OJ编号290:KevinFeng写作文。
#include
#include
using namespace std;
string add = "Add";
string del = "Del";
string rep = "Rep";
string a;
string op;
int opA;
char opB;
int opC;
int n, m;
int main()
{
while(cin >> n >> m)
{
cin >> a;
vector b;
int i;
for(i = 0; i < a.length(); ++i)
{
b.push_back(a[i]);
}
while(m--)
{
cin >> op;
if(op == add)
{
cin >> opA >> opB;
b.insert(b.begin()+opA-1, opB);
}
else if (op == del)
{
cin >> opA >> opC;
while(opC--)
{
b.erase(b.begin() + opA - 1);
}
}
else
{
cin >> opA >> opB;
b[opA - 1] = opB;
}
}
vector::iterator c;
for(c=b.begin();c!=b.end();c++)
{
cout << *c;
}
cout << endl;
}
}
看吧,vector的insert功能就是这么方便。一般如果我们需要对一个数组(或者链表)里面执行插入操作,请使用vector来减少代码量。
什么?你想写链表?用STL里的list?一个算法比赛用什么链表啊我的天哪(于是list就合理的不写了)
=====deque=====
DQ冰淇淋?
栈和队列都好写,因为它们都是单向增长或移动的。但是双端队列就不太好写了。这时候,我们需要合理运用deque的武器呢。
OJ编号314:毛毛虫。
#include
#include
#include
using namespace std;
deque > q;
bool flag;
int m, n;
int a, b;
int main()
{
while(~scanf("%d%d", &m, &n))
{
flag = true;
while (!q.empty())q.pop_back();
for (int i = 0; i < m; ++i)
{
scanf("%d%d", &a, &b);
q.push_back(make_pair(a, b));
}
while (n--)
{
scanf("%d%d", &a, &b);
q.pop_front();
q.push_back(make_pair(a, b));
}
if (q.front().first == q.back().first && q.front().second == q.back().second)
{
flag = false;
}
while (!q.empty())
{
printf("%d %d\n", q.back().first, q.back().second);
q.pop_back();
}
if (!flag)
{
puts("oh no");
}
}
}
OJ编号315:滚动的窗口。
#include
#include
using namespace std;
deque dmin;
deque dmax;
int a[100010];
int top;
inline void write(int x)
{
if(x < 0)putchar('-'),x=-x;
if (x > 9)write(x / 10);
putchar(x % 10 + 48);
}
inline int read()
{
int k = 0, f = 1;
char c = getchar();
while (c < '0' || c>'9')
{
if (c == '-')f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
k = (k << 1) + (k << 3) + c - 48;
c = getchar();
}
return k * f;
}
int n, k;
int main()
{
while(~scanf("%d%d", &n, &k))
{
int i;
for(i = 1; i <= n; ++i)a[i] = read();
while (!dmin.empty())dmin.pop_back();
for (i = 1; i <= k; ++i)
{
if (dmin.empty())dmin.push_back(i);
else
{
while (!dmin.empty() && a[dmin.back()] > a[i]) dmin.pop_back();
dmin.push_back(i);
}
}
write(a[dmin.front()]); putchar(' ');
for (i = k + 1; i <= n; ++i)
{
while (!dmin.empty() && dmin.front() <= i - k)dmin.pop_front();
if (dmin.empty())dmin.push_back(i);
else
{
while (!dmin.empty() && a[dmin.back()] > a[i]) dmin.pop_back();
dmin.push_back(i);
}
write(a[dmin.front()]); putchar(' ');
}
putchar('\n');
while (!dmax.empty())dmax.pop_back();
for (i = 1; i <= k; ++i)
{
if (dmax.empty())dmax.push_back(i);
else
{
while (!dmax.empty() && a[dmax.back()] < a[i]) dmax.pop_back();
dmax.push_back(i);
}
}
write(a[dmax.front()]); putchar(' ');
for (i = k + 1; i <= n; ++i)
{
while (!dmax.empty() && dmax.front() <= i - k)dmax.pop_front();
if (dmax.empty())dmax.push_back(i);
else
{
while (!dmax.empty() && a[dmax.back()] < a[i]) dmax.pop_back();
dmax.push_back(i);
}
write(a[dmax.front()]); putchar(' ');
}
putchar('\n');
}
}
当然,如果您非要开大空间从中间计数,或者取模,我也拦不住
=====set=====
在算法比赛里,能够用到set这种高级东西的,一般是非常困难的题目。
下面举几个例子:
OJ编号89:LCSDataEnhanced。
#include
#include
#include
#include
#include
using namespace std;
char A[110],B[110];
char tmp[110];
int n,m;
int dp[110][110];
int lasta[110][27];
int lastb[110][27];
int targetLen;
set ans;
void init()
{
memset(dp,0,sizeof(dp));
memset(lasta,0,sizeof(lasta));
memset(lastb,0,sizeof(lastb));
memset(tmp,0,sizeof(tmp));
ans.clear();
}
void buildDP()
{
int i;
for(i=1;i<=n;++i)
{
int j;
for(j=1;j<=m;++j)
{
if(A[i]==B[j])
{
dp[i][j]=dp[i][j]>(dp[i-1][j-1]+1)?dp[i][j]:(dp[i-1][j-1]+1);
}
else
{
dp[i][j]=dp[i-1][j]>dp[i][j-1]?dp[i-1][j]:dp[i][j-1];
}
}
}
targetLen=dp[n][m];
}
void buildLast()
{
int i;
for(i=1;i<=n;++i)
{
int j;
for(j=0;j<26;++j)
{
if(A[i]=='A'+j)
{
lasta[i][j]=i;
}
else
{
lasta[i][j]=lasta[i-1][j];
}
}
}
for(i=1;i<=m;++i)
{
int j;
for(j=0;j<26;++j)
{
if(B[i]=='A'+j)
{
lastb[i][j]=i;
}
else
{
lastb[i][j]=lastb[i-1][j];
}
}
}
}
void dfs(int i,int j,int len)
{
if(len<=0)
{
ans.insert(string(tmp+1));
return;
}
if(i>0&&j>0)
{
int k;
for(k=0;k<26;++k)
{
int t1=lasta[i][k];
int t2=lastb[j][k];
if(dp[t1][t2]==len)
{
tmp[len]='A'+k;
dfs(t1-1,t2-1,len-1);
}
}
}
}
void printAns()
{
set::iterator it;
for(it=ans.begin();it!=ans.end();++it)
{
puts((*it).c_str());
}
}
int main()
{
while(~scanf("%s%s",A+1,B+1))
{
init();
n=strlen(A+1);
m=strlen(B+1);
buildDP();
buildLast();
tmp[targetLen+1]='\0';
dfs(n,m,targetLen);
printAns();
}
}
OJ编号279:Z君的日常之集合处理。
#include
#include
#include
#include
using namespace std;
char tmp[3];
char op;
int t,n,m;
int tmpint;
int main()
{
while(~scanf("%d", &t))
{
while(t--)
{
scanf("%s%d%d",tmp,&n,&m);
op=tmp[0];
vector a,b;
int i;
for(i=0;i c;
set_union(a.begin(),a.end(),b.begin(),b.end(),back_inserter(c),less());
std::vector::iterator m;
for(m=c.begin();m!=c.end();m++)
{
printf("%d ",*m);
}
printf("\n");
}
else
{
vector c;
set_difference(a.begin(),a.end(),b.begin(),b.end(),back_inserter(c),less());
if(!c.empty())
{
std::vector::iterator m;
for(m=c.begin();m!=c.end();m++)
{
printf("%d ",*m);
}
printf("\n");
}
else
{
printf("empty\n");
}
}
}
}
}
OJ编号516:ModricWang的星灵棋。
#include
#include
#include
using namespace std;
set vis[5];
bool win[171];
struct State
{
unsigned char row[4],col[4];
unsigned char left,right;
unsigned char rc[2][2];
short step,turn;
};
bool putChess(struct State *s,const int r,const int c,unsigned char p)
{
unsigned char pl2r=p<<2*r,pl2c=p<<2*c,al2r=~(3<<2*r),al2c=~(3<<2*c);
s->row[r]&=al2c,s->row[r]|=pl2c;
if(win[s->row[r]])
{
return 1;
}
s->col[c]&=al2r,s->col[c]|=pl2r;
if(win[s->col[c]])
{
return 1;
}
if(r==c)
{
s->left&=al2c,s->left|=pl2c;
if(win[s->left])
{
return 1;
}
}
if(r+c==3)
{
s->right&=al2r,s->right|=pl2r;
if(win[s->right])
{
return 1;
}
}
return 0;
}
struct State q[666666];
int head;
int tail;
bool getChess(int r,int c)
{
if(r<0||c<0||r>3||c>3)
{
return 0;
}
else
{
return ((unsigned char)(q[head].row[r]>>2*c)&3)==q[head].turn;
}
}
void before(int first,int second,int kind)
{
q[tail]=q[head];
q[tail].rc[first][second]+=kind;
++q[tail].step;
}
void after()
{
if(!vis[q[head].turn+1].count(*(unsigned int*)q[tail].row))
{
vis[q[head].turn+1].insert(*(unsigned int*)q[tail].row);
q[tail].turn=3-q[head].turn;
tail++;
}
}
int main()
{
struct State src;
memset(&src,0,sizeof src);
win[170]=win[85]=1;
int firstzero=1;
int r;
for(r=0;r<4;++r)
{
char str[123];
scanf("%s",str);
int c;
for(c=0;c<4;++c)
{
switch(str[c])
{
case 'B':
if(putChess(&src,r,c,1))
{
puts("0");
return 0;
}
break;
case 'W':
if(putChess(&src,r,c,2))
{
puts("0");
return 0;
}
break;
case 'O':
if(firstzero)
{
src.rc[1][0]=r,src.rc[0][0]=c,firstzero=0;
}
else
{
src.rc[1][1]=r,src.rc[0][1]=c;
}
break;
}
}
}
head=0,tail=2;
q[0]=q[1]=src;
q[1].turn=2;
vis[2].insert(*(unsigned int*)src.row);
vis[3].insert(*(unsigned int*)src.row);
for(;head!=tail;head++)
{
if(getChess(q[head].rc[1][1]-1,q[head].rc[0][1]))
{
before(1,1,-1);
if(putChess(&q[tail],q[tail].rc[1][1],q[head].rc[0][1],0)||putChess(&q[tail],q[head].rc[1][1],q[head].rc[0][1],q[head].turn))
{
printf("%d",q[tail].step);
return 0;
}
after();
}
if(getChess(q[head].rc[1][1],q[head].rc[0][1]-1))
{
before(0,1,-1);
if(putChess(&q[tail],q[head].rc[1][1],q[tail].rc[0][1],0)||putChess(&q[tail],q[head].rc[1][1],q[head].rc[0][1],q[head].turn))
{
printf("%d",q[tail].step);
return 0;
}
after();
}
if(getChess(q[head].rc[1][1]+1,q[head].rc[0][1]))
{
before(1,1,1);
if(putChess(&q[tail],q[tail].rc[1][1],q[head].rc[0][1],0)||putChess(&q[tail],q[head].rc[1][1],q[head].rc[0][1],q[head].turn))
{
printf("%d",q[tail].step);
return 0;
}
after();
}
if(getChess(q[head].rc[1][1],q[head].rc[0][1]+1))
{
before(0,1,1);
if(putChess(&q[tail],q[head].rc[1][1],q[tail].rc[0][1],0)||putChess(&q[tail],q[head].rc[1][1],q[head].rc[0][1],q[head].turn))
{
printf("%d",q[tail].step);
return 0;
}
after();
}
if(getChess(q[head].rc[1][0]-1,q[head].rc[0][0]))
{
before(1,0,-1);
if(putChess(&q[tail],q[tail].rc[1][0],q[head].rc[0][0],0)||putChess(&q[tail],q[head].rc[1][0],q[head].rc[0][0],q[head].turn))
{
printf("%d",q[tail].step);
return 0;
}
after();
}
if(getChess(q[head].rc[1][0],q[head].rc[0][0]-1))
{
before(0,0,-1);
if(putChess(&q[tail],q[head].rc[1][0],q[tail].rc[0][0],0)||putChess(&q[tail],q[head].rc[1][0],q[head].rc[0][0],q[head].turn))
{
printf("%d",q[tail].step);
return 0;
}
after();
}
if(getChess(q[head].rc[1][0]+1,q[head].rc[0][0]))
{
before(1,0,1);
if(putChess(&q[tail],q[tail].rc[1][0],q[head].rc[0][0],0)||putChess(&q[tail],q[head].rc[1][0],q[head].rc[0][0],q[head].turn))
{
printf("%d",q[tail].step);
return 0;
}
after();
}
if(getChess(q[head].rc[1][0],q[head].rc[0][0]+1))
{
before(0,0,1);
if(putChess(&q[tail],q[head].rc[1][0],q[tail].rc[0][0],0)||putChess(&q[tail],q[head].rc[1][0],q[head].rc[0][0],q[head].turn))
{
printf("%d",q[tail].step);
return 0;
}
after();
}
}
}
这些题都太难了,唉
=====map=====
=====priority_queue=====
来跟我一起念!PO-RI-O-RI-TI-KYU!(罗马音:ポリオリティキュ!)
是的。如果你不把第一个连读音节拆开念的话,一定会忘记打一个字母小r的。这可是惨痛的教训啊——
**优先队列**的本质是一个堆(二叉树),并且是**大顶堆**。与其他STL不同,数据结构课用的不多,但是在算法课上最经常用到。
在诸多算法里都会用优先队列来优化算法,尤其是**贪心算法**,在各种贪心算法中都会见到。比如著名的最短路Dijkstra。
在这里就不写了。参见[[广度优先搜索_bfs_与标数最短路_dijkstra]]。
这个文中也提到,如何将默认大顶堆**转换为小顶堆**呢?**取相反数**存储与读取就完了。这是个很经典的技巧,相比之下在定义中修改优先级略为难记。
不过一定要记得读取的时候也要取相反——存的时候是反着存的,很容易忘。
对于带结构体的优先队列,如果不想引入大小判定符号,也没有字典序这种糟糕的条件,就嵌套使用**pair**吧!默认结构体pair的优先级默认是先比较first再比较second,省得再写难记的大小判定了!