今天没干别的就是刷题,栈队列和树都刷了几道,感觉有那么一点点感觉了。
1.
P5788 【模板】单调栈P5788 【模板】单调栈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn),早上做的题,感觉就有点遗忘了,在网上找到了伪代码,自己当时做这道题的时候完全跟着视频讲解的思路做的,当时看完还觉得没任何问题了,这一到晚上又忘了一些了,等会还得去再看一遍。
stack<int> st;
//此处一般需要给数组最后添加结束标志符,具体下面例题会有详细讲解
for (遍历这个数组)
{
if (栈空 || 栈顶元素大于等于当前比较元素)
{
入栈;
}
else
{
while (栈不为空 && 栈顶元素小于当前元素)
{
栈顶元素出栈;
更新结果;
}
当前数据入栈;
}
}
#include<bits/stdc++.h>
using namespace std;
int main()
{
int i,j,k,n,s,a[100],b[100],c[100]={0};
stack<int>st;
cin>>n;
for(i=1;i<=n;i++)
{cin>>a[i];}
st.push(0);
for(i=n;i>=1;i--)
{
while(!st.empty()&&a[st.top()]<=a[i])
{
st.pop();
}
c[i]=st.empty()?0:st.top();
st.push(i);
}
for(i=1;i<=n;i++)
{
cout<<c[i];
cout<<" ";
}
}
2.P1449 后缀表达式P1449 后缀表达式 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
对于这个题而言,主要是要考虑在后缀表达式中每一个符号对应的只是前面的两个值,若为3 2 1- +就是先算2-1得到1重新入栈然后在算3+1得到4这么一个逻辑,还是就是在大得while循环当中要确保每循环一次让left得值归零。
#include<bits/stdc++.h>
using namespace std;
stack<int>s;
int main()
{
int i,j,k,sum,p,left,right;
char c;
cin>>c;
while(c!='@')
{ left=0; //这里的left和right代表的是一个等式的左值和右值
if(c<='9'&&c>='0')
while(c<='9'&&c>='0')
{
k=c-'0';
left=left*10+k;
cin>>c;
}
if(c=='.'){s.push(left);}
else{
right=s.top();s.pop();
left=s.top();s.pop();
if(c=='+'){s.push(left+right);}
if(c=='-'){s.push(left-right);}
if(c=='*'){s.push(left*right);}
if(c=='/'){s.push(left/right);}
}
cin>>c;
}
cout<<s.top();
}
对于栈的话还做了两三道入门题,就是简单的括号匹配和栈的输出,也没啥必要写出来,没啥价值。
4.P1223 排队接水P1223 排队接水 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这道题一看就是队列题,但是自己一直没读懂题目,这道题主要是要理解总的接水时间是(n-1)*time+(n-2)*time...这么依次下去,所以对于开头应该是时间最短得才对,用c++的话直接用sort函数降序排列即可,还有一个要想到的就是要用到结构体来储存各个学生的下标和接水时间。一开始没有思路就是总接水时间想不明白。
#include<bits/stdc++.h>
using namespace std;
struct per
{
int time;
int num;
}p[1001];
bool cmp(per p1,per p2) //cmp函数在应用时要根据题目所变化
{
return p1.time<p2.time;
}
int main()
{
int i,j,k,m,n;
double ave,s;
cin>>n;
for(i=1;i<=n;i++)
{
cin>>p[i].time;
p[i].num=i;
}
sort(p+1,p+n+1,cmp);
for(i=1;i<=n;i++)
{
cout<<p[i].num<<" ";
s+=(n-i)*p[i].time;
}
cout<<endl;
ave=s/n;
printf("%.2f",ave);
return 0;
}
5. P1996 约瑟夫问题P1996 约瑟夫问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)、
我记着这题以前期末的时候好像做过作业但是已经忘光了。一开始想着是用队列,但是一直没想通是怎么一个变法,看了下解析一下就通了,就是先让两个队首的元素插入到队尾去,然后输出目前队首的元素并让他出列,接下来依次解决,
#include<bits/stdc++.h>
using namespace std;
int main()
{
queue<int>q;
int i,j,k=0,n,m;
cin>>n>>m;
for(i=1;i<=n;i++)
{
q.push(i);
}
while(k<n)
{
for(i=1;i<m;i++)
{
q.push(q.front()); //这里感觉用的很巧妙啊
q.pop();
}
cout<<q.front()<<" ";
q.pop();k++;
}
return 0;
}
还有一种方法讲解就是用数组来做,首先定义一个用于标记的数组,其中的容易踩的坑就是now+1那个位置,因为now一直加1是有可能大于n的数值的,所以当now数值大于10后因自动将now转化为1,这里就是稍微难理解的一点,对于这种方法他是将标记了的也相当于进行了判断,而第一种队列来说直接就出列了不用管,而且更好理解。
#include<bits/stdc++.h>
using namespace std;
int main()
{
queue<int>q;
int n,m,round[200]={0},now=0,k=0;
cin>>n>>m;
while(k<n)
{
for(int i=1;i<=m;i++)
{
now=(now+1>n?1:now+1);
while(round[now]==1){now=(now+1>n?1:now+1);}
}
k++;round[now]=1;
cout<<now<<" ";
}
return 0;
}
这种方法还是大不如队列,现在我还是能稍微理解,估计过一阵,还是根本看不懂,还是队列好使。
6. P1030 [NOIP2001 普及组] 求先序排列P1030 [NOIP2001 普及组] 求先序排列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
string中find()返回值是字母在母串中的下标位置。
substr()是C++语言的函数,主要功能是复制子字符串,要求从指定位置开始,并具有指定的长度。
这题我拿到反正是一点思路都没有,看了半天题解也没看明白,最后还是看视频才稍微懂了懂,这题突破点就是找根,后序遍历的最后一个一定是根结点,这题还学了两个c++关于字符串的函数,对于dfs函数来说的话,我一开始都没怎么看懂为什么要这样搞,后来才发现原来就是求各个子树的结点,顺序的话就是按照先序的顺序来的,最开始是根节点然后是左子树,最后右子树
#include<bits/stdc++.h>
using namespace std;
void dfs(string s1,string s2)
{
if(s1.size()==0)return ;
int len=s1.size();
char root=s2[len-1];
int p=s1.find(root);
string s1l=s1.substr(0,p),s1r=s1.substr(p+1,len-p-1);
string s2l=s2.substr(0,p),s2r=s2.substr(p,len-p-1);
cout<<root;
dfs(s1l,s2l);
dfs(s1r,s2r);
}
int main()
{
string s1,s2;
int i,j,k,n,m;
cin>>s1>>s2;
dfs(s1,s2);
}
7.P1827 [USACO3.4] 美国血统 American HeritageP1827 [USACO3.4] 美国血统 American Heritage - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
美国血统这一道题就和此题一摸一样,无非就是在求左右子树的时候将位置换了需要改一下还有就是他是求后序遍历,在dfs顺序那里互换一下即可。这题一做记忆加固!
#include<bits/stdc++.h>
using namespace std;
void dfs(string s1,string s2)
{
if(s1.size()==0)return ;
int len=s1.size();
char root=s2[0];
int p=s1.find(root);
string s1l=s1.substr(0,p),s1r=s1.substr(p+1,len-p-1);
string s2l=s2.substr(1,p),s2r=s2.substr(p+1,len-p-1);
dfs(s1l,s2l);
dfs(s1r,s2r);
cout<<root;
}
int main()
{
string s1,s2;
int i,j,k,n,m;
cin>>s1>>s2;
dfs(s1,s2);
}
8. B3642 二叉树的遍历B3642 二叉树的遍历 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这个题一做,发现自己对于树最基本的建立都有点小问题,一直搞了半天才懂。对于遍历的话就简单了。
#include<bits/stdc++.h>
using namespace std;
typedef struct node
{
int num;
int l;
int r;
}node;
void preorder(node *t)
{
if(t->num!=0)
{
cout<<t->num<<" ";
preorder(t-t->num+t->l);
preorder(t-t->num+t->r);
}
}
void inorder(node *t)
{
if(t->num!=0)
{
inorder(t-t->num+t->l);
cout<<t->num<<" ";
inorder(t-t->num+t->r);
}
}
void postorder(node *t)
{
if(t->num!=0)
{
postorder(t-t->num+t->l);
postorder(t-t->num+t->r);
cout<<t->num<<" ";
}
}
int main()
{
int n,i,j,k,s,a,b;
cin>>n;
node *tree=(node*)malloc((n+1)*sizeof(node));
tree[0].num=0;
for(i=1;i<=n;i++)
{
tree[i].num=i;
cin>>tree[i].l>>tree[i].r;
}
preorder(tree+1);
cout<<endl;
inorder(tree+1);
cout<<endl;
postorder(tree+1);
}