P4715
#include<bits/stdc++.h>
using namespace std;
struct Node
{
int bian;
int neng=0;
};
int main()
{
Node lmax;
Node rmax;
Node a;
int n;
cin>>n;
for(int i=0;i<1<<(n-1);i++)
{
cin>>a.neng ;
if(a.neng >lmax.neng )
{
lmax.neng =a.neng ;
lmax.bian =i+1;
}
}
for(int i=1<<(n-1);i<1<<(n);i++)
{
cin>>a.neng ;
if(a.neng >rmax.neng )
{
rmax.neng =a.neng ;
rmax.bian =i+1;
}
}
if(rmax.neng >lmax.neng ) cout<<lmax.bian ;
else
cout<<rmax.bian ;
return 0;
}
或许就是对半,各自找到最厉害的?
#include<iostream>
#include<queue>
#include<map>
using namespace std;
int main(){
int n;
queue<pair<int,int> > q; //pair是stl中的数据结构,这里用first表示国家号,second表示国家实力
cin>>n;
n=1<<n; //位运算,等价与n=pow(2,n)(位运算更快)
for(int i=1;i<=n;i++){
int x;
cin>>x;
q.push(make_pair(i,x)); //make_pair(i,x)就是建立一个first为i,second为x的pair
}
while(q.size()>2){ //循环将比赛进行至只剩前两名(q.size()为2是时要跳出循环单独判断亚军)
pair<int,int> x,y;
x=q.front();
q.pop();
y=q.front();
q.pop();
if(x.second>y.second){ //从队头取出两个队,进行比较后将较强的队压入队尾
q.push(x);
}else{
q.push(y);
}
}
pair<int,int> x,y;
x=q.front();
q.pop();
y=q.front();
q.pop();
if(x.second>y.second){ //较弱的那队时亚军,将其国家号输出
cout<<y.first<<endl;
}else{
cout<<x.first<<endl;
}
return 0;
}
P4913
#include<bits/stdc++.h>
using namespace std;
int Max=-1;
struct node
{
int left,right;
}a[1000000];
void dfs(int root,int step)
{
if(root==0)
return;
Max=max(Max,step);
dfs(a[root].left,step+1);
dfs(a[root].right,step+1);
}
int main()
{
int m;
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>a[i].left >>a[i].right ;
}
dfs(1,1);
cout<<Max;
return 0;
}
构造树,树有两个结点,两个节点又可以作为下一个的根,所以依次遍历,记忆化搜索,每次增加1,左右取最值
P1827
根据中序遍历,前序遍历推后序遍历
前序遍历的第一个是根节点,之后的每一个其实都是相对的根节点
中序遍历根节点左右自然形成·左右树
所以后序遍历是先左子树再右子树,再根节点
每一个子树参数分别是前序中序各自的
#include<iostream>
#include<string>
using namespace std;
string a,b;
int i;
void houxu(int x,int y,int p,int q)//x,y是前序,p,q是中序
{
if(x>y||p>q) return ;///人家遍历完了,就是说先让左子树走然后继续让右子树走,然后
else
{
int i=b.find(a[x]);
houxu(x+1,x+i-p,p,i-1);
houxu(x+i-p+1,y,i+1,q);
cout<<a[x];
}
}
int main()
{
cin>>b>>a;
int l=a.length()-1;
houxu(0,l,0,l);
return 0;
}
houxu(x+1,x+i-p,p,i-1);
houxu(x+i-p+1,y,i+1,q);
前面两个参数是前序遍历,+1表示取掉了一个了,i-p其实是根据中序遍历里面左子树的个数,前序遍历也是优先左子树的啊!!!啊我突然悟了,之前一直不理解
后序遍历是左右根
/还是不懂,今晚回去复习这个!!!!
P1030
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
char s1[10];
char s2[10];
int len;
inline int find(char ch)
{
for(int i=0;i<len;i++)
{
if(s1[i]==ch) return i;
}
}
void dfs(int l1,int r1,int l2,int r2)
{
int m=find(s2[r2]);
cout<<s2[r2];
if(m>l1) dfs(l1,m-1,l2,r2-r1+m-1);
if(m<r1) dfs(m+1,r1,l2+m-l1,r2-1);
}
int main()
{
cin>>s1;
cin>>s2;
len=strlen(s1);
dfs(0,len-1,0,len-1);
}
P5076
//查询排名:lower_bound
//排名为x:
//前驱:lower_bound
//后继:upper_bound
/*
#include<iostream>
#include<set>
using namespace std;
multiset<int>q;
void charu(int b)
{
q.insert(b);
}
void chaxun(int b)
{
multiset<int>::iterator it,i;
it=q.lower_bound(b);
int order=0;
for(i=q.begin();i!=it;i++,order++);
cout<<order<<endl;
}
void zhaoshu(int b)
{
int order=-1;
multiset<int>::iterator it,i;
for(it=q.begin();it!=q.end();it++)
{
order++;
if(order==b)
{
cout<<*it<<endl;
break;
}
}
}
void qianqu(int b)
{
multiset<int>::iterator it;
it=q.lower_bound(b);
cout<<*--it<<endl;
}
void houji(int b)
{
multiset<int>::iterator it;
it=q.upper_bound(b);
cout<<*it<<endl;
}
int main()
{
q.insert(-0x7ffffff);
q.insert(0x7ffffff);
int m,a,b;
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>a>>b;
switch(a)
{
case 1:
chaxun(b);
break;
case 2:
zhaoshu(b);
break;
case 3:
qianqu(b);
break;
case 4:
houji(b);
break;
case 5:
charu(b);
break;
}
}
return 0;
} */
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<set>
using namespace std;
multiset<int>q;
int n,t,x,order;
int main()
{
q.insert(-0x7fffffff);
q.insert(0x7fffffff);
scanf("%d",&n);
while(n--)
{
scanf("%d%d",&t,&x);
if(t==1)
{
auto it=q.lower_bound(x);
order=0;
for(auto i=q.begin();i!=it;i++,order++);
printf("%d\n",order);
}
else if(t==2)
{
order=-1;
for(int i:q)
if(++order==x)
printf("%d\n",i);
}
else if(t==3)
{
auto it=q.lower_bound(x);
printf("%d\n",*--it);
}
else if(t==4)
{
printf("%d\n",*q.upper_bound(x));
}
else
{
q.insert(x);
}
}
return 0;
}
只能说multiset+stl yyds了
当然还是要感受一下大佬的做法,树到底是个啥
void add(int x,int v)
{
tree[x].siz++;
//如果查到这个节点,说明这个节点的子树里面肯定是有v的,所以siz++
if(tree[x].val==v){
//如果恰好有重复的数,就把cnt++,退出即可,因为我们要满足第四条性质
tree[x].cnt++;
return ;
}
if(tree[x].val>v){//如果v<tree[x].val,说明v实在x的左子树里
if(tree[x].ls!=0)
add(tree[x].ls,v);//如果x有左子树,就去x的左子树
else{//如果不是,v就是x的左子树的权值
cont++;//cont是目前BST一共有几个节点
tree[cont].val=v;
tree[cont].siz=tree[cont].cnt=1;
tree[x].ls=cont;
}
}
else{//右子树同理
if(tree[x].rs!=0)
add(tree[x].rs,v);
else{
cont++;
tree[cont].val=v;
tree[cont].siz=tree[cont].cnt=1;
tree[x].rs=cont;
}
}
}
找前驱
int queryfr(int x, int val, int ans) {
if (tree[x].val>=val)
{//如果当前值大于val,就说明查的数大了,所以要往左子树找
if (tree[x].ls==0)//如果没有左子树就直接返回找到的ans
return ans;
else//如果不是的话,去查左子树
return queryfr(tree[x].ls,val,ans);
}
else
{//如果当前值小于val,就说明我们找比val小的了
if (tree[x].rs==0)//如果没有右孩子,就返回tree[x].val,因为走到这一步时,我们后找到的一定比先找到的大(参考第二条性质)
return (tree[x].val<val) ? tree[x].val : ans
//如果有右孩子,,我们还要找这个节点的右子树,因为万一右子树有比当前节点还大并且小于要找的val的话,ans需要更新
if (tree[x].cnt!=0)//如果当前节数的个数不为0,ans就可以更新为tree[x].val
return queryfr(tree[x].rs,val,tree[x].val);
else//反之ans不需要更新
return queryfr(tree[x].rs,val,ans);
}
}
找后继
int queryne(int x, int val, int ans) {
if (tree[x].val<=val)
{
if (tree[x].rs==0)
return ans;
else
return queryne(tree[x].rs,val,ans);
}
else
{
if (tree[x].ls==0)
return (tree[x].val>val)? tree[x].val : ans;
if (tree[x].cnt!=0)
return queryne(tree[x].ls,val,tree[x].val);
else
return queryne(tree[x].ls,val,ans);
}
}
按值找排名
int queryval(int x,int val)
{
if(x==0) return 0;//没有排名
if(val==tree[x].val) return tree[tree[x].ls].siz;
//如果当前节点值=val,则我们加上现在比val小的数的个数,也就是它左子树的大小
if(val<tree[x].val) return queryval(tree[x].ls,val);
//如果当前节点值比val大了,我们就去它的左子树找val,因为左子树的节点值一定是小的
return queryval(tree[x].rs,val)+tree[tree[x].ls].siz+tree[x].cnt;
//如果当前节点值比val小了,我们就去它的右子树找val,同时加上左子树的大小和这个节点的值出现次数
//因为这个节点的值小于val,这个节点的左子树的各个节点的值一定也小于val
}
//注:这里最终返回的是排名-1,也就是比val小的数的个数,在输出的时候记得+1
按排名找值
int queryrk(int x,int rk)
{
if(x==0) return INF;
if(tree[tree[x].ls].siz>=rk)//如果左子树大小>=rk了,就说明答案在左子树里
return queryrk(tree[x].ls,rk);//查左子树
if(tree[tree[x].ls].siz+tree[x].cnt>=rk)//如果左子树大小加上当前的数的多少恰好>=k,说明我们找到答案了
return tree[x].val;//直接返回权值
return queryrk(tree[x].rs,rk-tree[tree[x].ls].siz-tree[x].cnt);
//否则就查右子树,同时减去当前节点的次数与左子树的大小
}
P1364
#include<bits/stdc++.h>
using namespace std;
int main()
{
int m,g[105][105],a[1000],l,r,min;
cin>>m;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
g[i][j]=1000000;
}
for(int i=1;i<=m;i++)
{
g[i][i]=0;
cin>>a[i]>>l>>r;
if(l>0) g[i][l]=g[l][i]=1;
if(r>0) g[i][r]=g[r][i]=1;
}
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
for(int p=1;p<=m;p++)
if(g[i][j]>g[i][p]+g[p][j]&&i!=j&&p!=j)
{
g[i][j]=g[i][p]+g[p][j];
}
}
}
min=0x7fffffff;
for(int i=1;i<=m;i++)
{
int total=0;
for(int j=1;j<=m;j++)
{
total+=g[i][j]*a[j];
}
if(total<min)min=total;
}
printf("%d",min);
return 0;
}
二叉树就是有向图啊,所以就相当于找单元最短路径,啊痛苦回忆
floyed yyds
稍微解释一下,一开始大家都无穷大,然后连接各边并赋值,然后三层循环尝试
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
bool g[105][105]={0}; //这里n小我就直接邻接矩阵了,如果用邻接表还能快点
bool v[105]={0};
int n,num[105],ans=1<<30;
struct node{
int u,step;
};
int bfs(int x){ //bfs找当前点x为医院设置点时的总距离
memset(v,0,sizeof(v));
queue<node> q;
v[x]=1;
q.push((node){x,0});
int sum=0;
while(!q.empty()){
node now=q.front();
q.pop();
for(int i=1;i<=n;i++)
if(g[now.u][i]&&!v[i]){
node next={i,now.step+1};
sum+=num[i]*next.step;
v[i]=1;
q.push(next);
}
}
return sum;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
int a,l,r;
scanf("%d%d%d",&a,&l,&r);
num[i]=a;
if(l) g[i][l]=g[l][i]=1;
if(r) g[i][r]=g[r][i]=1;
}
for(int i=1;i<=n;i++)
ans=min(ans,bfs(i));
printf("%d",ans);
return 0;
}
看一个spfa
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 11000
using namespace std;
int head[maxn],team[maxn],exist[maxn],dis[maxn],minn=0x7ffff;
int n,sum,p[maxn];
int read()
{
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
struct EDGE
{
int next;
int to;
int co;
}edge[maxn*3];
int qr;
void add(int from,int to,int co)
{
edge[++qr].next=head[from];
edge[qr].to=to;
edge[qr].co=co;
head[from]=qr;
}
void spfa(int x)
{
memset(dis,0x7f,sizeof(dis));
memset(exist,0,sizeof(exist));
int h=0,t=1;
dis[x]=0;exist[x]=1;team[1]=x;
while(h<t)
{
h++;
int u=team[h];exist[u]=0;
for(int i=head[u];i!=0;i=edge[i].next)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].co)
{
dis[v]=dis[u]+edge[i].co;
if(!exist[v])
{
exist[v]=1;
t++;
team[t]=v;
}
}
}
}
}
int main()
{
n=read();
for(int i=1;i<=n;++i)
{
int l,r;
p[i]=read();
l=read();r=read();
if(l!=0) add(i,l,1),add(l,i,1);
if(r!=0) add(i,r,1),add(r,i,1);
}
for(int i=1;i<=n;++i)
{
spfa(i);sum=0;
for(int j=1;j<=n;++j)
{
// printf("***%d\n",dis[j]*p[j]);
sum+=dis[j]*p[j];
}
minn=min(minn,sum);
}
printf("%d",minn);
return 0;
}
P1229
为什么不能确定呢?因为若一个根节点只有一个子节点,那么左右影响不了
前序 根左右 后序 左右根 中序 左根右
题目转化成找只有一个儿子的节点个数
前序中ab,后续中ba,则只有一个儿子
2^
在这里插入代码#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int ans;
char str1[233],str2[233];
int main()
{
scanf("%s",str1);
scanf("%s",str2);
for(int i=0;i<strlen(str1);i++)
for(int j=1;j<strlen(str2);j++)
if(str1[i]==str2[j]&&str1[i+1]==str2[j-1])
ans++;
printf("%d",1<<ans);
return 0;
}
p1305
输入一串二叉树,输出其前序遍历。
输入格式
第一行为二叉树的节点数 nn。(1 \leq n \leq 261≤n≤26)
后面 nn 行,每一个字母为节点,后两个字母分别为其左右儿子。特别地,数据保证第一行读入的节点必为根节点。
空节点用 * 表示
输入格式
第一行为二叉树的节点数 nn。(1 \leq n \leq 261≤n≤26)
后面 nn 行,每一个字母为节点,后两个字母分别为其左右儿子。特别地,数据保证第一行读入的节点必为根节点。
空节点用 * 表示
#include<iostream>
using namespace std;
char a[30][30];
int m;
void qian(char t)
{
if(t!='*')
{cout<<t;
for(int i=1;i<=m;i++)
{
if(a[i][0]==t)
{
qian(a[i][1]);
qian(a[i][2]);
}
}
}
return ;
}
int main()
{
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>a[i][0]>>a[i][1]>>a[i][2];
}
// cout<<a[1][0];
qian(a[1][0]);
}
这种相当于直接搜索,输入进来左右子树,然后前序,就是先输出头,然后左右树递归,函数里面,通过输入的头结点,来搜索它的左子树右子树,再把左子树右子树递归,每一次都是输出
// 二叉树的先序遍历。
void PreOrder(TBTTree TT)
{
if (TT == NULL) return;
visit(TT); // 访问子树TT的根结点。
PreOrder(TT->lchild); // 遍历左子树。
PreOrder(TT->rchild); // 遍历右子树。
}
// 二叉树的中序遍历。
void InOrder(TBTTree TT)
{
if (TT == NULL) return;
InOrder(TT->lchild); // 遍历左子树。
visit(TT); // 访问子树TT的根结点。
InOrder(TT->rchild); // 遍历右子树。
}
// 二叉树的后序遍历。
void PostOrder(TBTTree TT)
{
if (TT == NULL) return;
PostOrder(TT->lchild); // 遍历左子树。
PostOrder(TT->rchild); // 遍历右子树。
visit(TT); // 访问子树TT的根结点。
}