1. 程式人生 > 其它 >樹上問題--基礎二叉樹

樹上問題--基礎二叉樹

前言:

這一章涉及很多樹的基礎知識,尤其是前序遍歷,中序遍歷,後序遍歷。程式碼中的遞迴思想還蠻重要的。

重要知識點:

知道前序遍歷和中序遍歷,就能確定後序遍歷。

知道後序遍歷和中序遍歷,就能確定前序遍歷。

知道前序遍歷和後序遍歷,無法確定中序遍歷。

例題:

1.P1087 [NOIP2004 普及組] FBI 樹 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

水題?

#include <iostream>
using namespace std;
char s[1050];
void maketree(int x,int y)
{
    if(y>x)
    {
        maketree(x,(x
+y)/2); maketree((x+y+1)/2,y); } int B=1,I=1; for(int i=0;i<=y-x;i++) { if(s[x+i]=='1') { B=0; }else if(s[x+i]=='0') { I=0; } } if(B) { cout<<'B'; } else if(I) { cout
<<'I'; } else { cout<<'F'; } } int main() { int n; cin>>n>>s; maketree(0,(1<<n)-1); return 0; }

2.P1030 [NOIP2001 普及組] 求先序排列 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

突破點就是後序遍歷的最後一個為根

#include<bits/stdc++.h>
using namespace std;
char s1[10
],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,l2+(m-1-l1)); 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); return 0; }

3.P1305 新二叉樹 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

看程式碼,還挺精彩的

#include<bits/stdc++.h>
using namespace std;
int n;
string s;
int main()
{
    cin>>n;
    cin>>s;
    for(int i=2;i<=n;++i)
    {
        string ss;
        cin>>ss;
        int x=s.find(ss[0]);
        s.erase(x,1);
        s.insert(x,ss);
    }
    for(int i=0;i<s.size();++i)
    if(s[i]!='*') cout<<s[i];
    else continue;
}

4.P1229 遍歷問題 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

如果在前序遍歷中有”AB“,後續遍歷中有”BA“,那麼說明A的兒子B可以時左兒子,也可以是右兒子,那麼方案數乘二。

#include<bits/stdc++.h>
using namespace std;
int ans;
char str1[500],str2[500];
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;
}

5.P5018 [NOIP2018 普及組] 對稱二叉樹 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

遞迴遞迴

#include<bits/stdc++.h>
using namespace std;
int ans,v[1000010],n;
struct
{
    int l,r;
}t[2000020];
int size[1000010];
void dfs(int u)
{
    size[u]=1;
    if(t[u].l!=-1)
    {
        dfs(t[u].l);
        size[u]+=size[t[u].l];
    }
    if(t[u].r!=-1)
    {
        dfs(t[u].r);
        size[u]+=size[t[u].r];
    }
}
bool check(int lson,int rson)
{
    if(lson==-1 && rson==-1) return 1;
    if(lson!=-1 && rson!=-1 && v[lson]==v[rson] && check(t[lson].l,t[rson].r) && check(t[lson].r,t[rson].l))
    return 1;
    return 0;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>v[i];
    for(int i=1;i<=n;i++) 
    {
        cin>>t[i].l>>t[i].r;
    }
    dfs(1);
    int ans=0;
    for(int i=1;i<=n;i++)
    if(check(t[i].l,t[i].r))
    ans=max(ans,size[i]);
    cout<<ans;
    return 0;
}

6.P5597 【XR-4】復讀 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

因為我發現我組織不了措辭,所以請自行題解區:P5597 【XR-4】復讀 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

有個精髓就是二叉樹的合併,ans=min((cnt-1)*2-dep);

#include<bits/stdc++.h>
using namespace std;
int ans=99999999,cnt1,cnt2,pos1,pos2;
struct 
{
    int l,r;
}t[100010],t2[100010];
int input()
{
    int ch=getchar()-'0',u=++cnt1;
    if(ch==3)
    {
        t[u].l=input();
        t[u].r=input();
    }
    if(ch==2)
    {
        t[u].r=input();
    }
    if(ch==1)
    {
        t[u].l=input();
    }
    return u;
}
void dfs(int u1,int u2)
{
    if(u1==pos1 || u2==pos2)
    {
        pos2=u2;
        u2=1;
    }
    if(t[u1].l)
    {
        if(!t2[u2].l) t2[u2].l=++cnt2;
        dfs(t[u1].l,t2[u2].l);
    }
    if(t[u1].r)
    {
        if(!t2[u2].r) t2[u2].r=++cnt2;
        dfs(t[u1].r,t2[u2].r);
    }
}
void solve(int u,int dep)
{
    pos1=u;
    pos2=0;
    memset(t2,0,sizeof(t2));
    dfs(1,cnt2=1);
    ans=min(ans,(cnt2-1)*2-dep);
    if(t[u].l)
    {
        solve(t[u].l,dep+1);
    }
    if(t[u].r)
    {
        solve(t[u].r,dep+1);
    }
}
int main()
{   
    input();
    solve(1,0);
    cout<<ans<<endl;
    return 0;
}