樹上問題--基礎二叉樹
阿新 • • 發佈:2021-08-24
前言:
這一章涉及很多樹的基礎知識,尤其是前序遍歷,中序遍歷,後序遍歷。程式碼中的遞迴思想還蠻重要的。
重要知識點:
知道前序遍歷和中序遍歷,就能確定後序遍歷。
知道後序遍歷和中序遍歷,就能確定前序遍歷。
知道前序遍歷和後序遍歷,無法確定中序遍歷。
例題:
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; }