二叉树

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的根结点。
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值