5 树&并查集 专题

文章介绍了多种与树和图相关的算法问题,包括二叉搜索树的构建、遍历和性质验证,有向无环图的最深根节点查找,完全二叉树的判断,以及并查集在判断连通性和构建树结构中的应用。此外,还涉及到了二叉树的插入操作和平衡性检查,以及路径之和等问题。
摘要由CSDN通过智能技术生成

前置知识

树的结构:[[2链表、邻接表]]
并查集:[[4并查集]]

#根据前序中序得后序

#二叉搜索树的中序遍历是递增的。

#完全二叉树用一维数组表示


1、叶节点数量✔

1004 Counting Leaves

// #include<iostream>
// #include<vector>
// #include<map>
// using namespace std;

// struct node{
//     int weight;
//     vector<int> child;   //指针域;
// };

// vector<int> ans(100,0);
// int max_level=0;
// void BFS(int root,int level,vector<node> nodes){
//     if (level>max_level) max_level=level;
//     if(nodes[root].child.size()==0) ans[level]+=1;
//     else{
//         for(auto it=nodes[root].child.begin();it!=nodes[root].child.end();it++){
//             BFS(*it,level+1,nodes);
//         }
//     }
// }

// int main()
// {
//     int n,m;
//     cin>>n>>m;
//     if(n==0) {
//         cout<<1;
//         return 0;
//     }
//     int max_level=1;
//     map<string,int> level;
//     vector<int> leaf_node_num(100,0); 
//     level["01"]=1;
//     leaf_node_num[1]=1;
//     for(int i=0;i<m;i++){
//         string x;
//         int k;
//         cin>>x>>k;
//         leaf_node_num[ level[x] ]-=1;
//         for(int j=0;j<k;j++){
//             string x_son;
//             cin>>x_son;
//             level[x_son]=level[x]+1;
//             if(level[x_son]>max_level) max_level=level[x_son];
//             leaf_node_num[ level[x_son] ]+=1;
//         }
//     }
    
//     for(int i=1;i<=max_level;i++){
//         cout<<leaf_node_num[i];
//         if(i!=max_level) cout<<" ";
//     }
    
//     int n,m;
//     cin>>n>>m;
//     vector<node> nodes(n+1);
//     for(int i=0;i<m;i++){
//         int x,k;
//         cin>>x>>k;
//         for(int j=0;j<k;j++){
//             int x_son;
//             cin>>x_son;
//             nodes[x].child.push_back(x_son);
//         }
//     }
//     BFS(1,1,nodes);
//     for(int i=1;i<=max_level;i++){
//         cout<<ans[i];
//         if(i!=max_level) cout<<" ";
//     }
    
// }


#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;

const int N = 100+10,M=2*N;

int head[N];
int val[N],ne[N];
int idx=0;

void add(int a,int b){
    val[idx] = b;
    ne[idx] = head[a];
    head[a] = idx++;
}

vector<int> ans;
queue<int> Q;
int visited[N];
void bfs(){
    Q.push(1);
    while(!Q.empty()){
        int n = Q.size();
        int cnt=0;
        while(n--){
            int  v = Q.front();Q.pop();
            if (head[v]==-1) cnt++;
            for(int idxx = head[v]; idxx !=-1; idxx =ne[idxx]){
                int v = val[idxx];
                if(!visited[v ]) Q.push(v),visited[v]=1;
            }
        }
        ans.push_back(cnt);
        
    }


    
}

int main(){
    memset(head,-1,sizeof head);
    int n,m;
    cin>>n>>m;
    for(int i=0;i<m;i++){
        int a,k;
        cin>>a>>k;
        while(k--){
            int b;
            cin>>b;
            add(a,b);
        }
    }
    bfs();
    for(int i=0;i<ans.size();i++){
        if(i==ans.size()-1) cout<<ans[i]<<endl;
        else cout<<ans[i]<<" ";
    }
    
    
}







2、树的遍历✔

根据后续和中序建树,并输出层序遍历。 #根据前序中序得后序 这个是建树
1020 Tree Traversals

#include<iostream>
#include<unordered_map>
#include<cstring>
#include<queue>
using namespace std;

const int N = 40;
int post[N],in[N];
unordered_map<int,int> pos;

int head[N*N],val[N*N],ne[N*N];
int idx=0;

void add(int a,int b){
    val[idx] = b;
    ne[idx] = head[a];
    head[a] =idx;
    idx ++;
}

int build(int pl,int pr,int il,int ir){

    int root = post[pr];int mid = pos[root];
    if(mid <ir ) add(root,build(pl+(mid-1-il)+1,pr-1,mid+1,ir));
    if(mid > il ) add(root,build(pl,pl+mid-1-il,il,mid-1));
    
    return root;  
} 


queue<int> Q;
void bfs(int root){
    Q.push(root);cout<<root;
    while(!Q.empty()){
        int v = Q.front();Q.pop();
        for(int idxx = head[v];idxx != -1;idxx = ne[idxx]){
            int child = val[idxx];
                cout<<" "<<child;
                Q.push(child);
        }
    }
}

int main(){
    memset(head,-1,sizeof head);
    int n;
    cin>>n;
    for(int i =0;i<n;i++){
        cin>>post[i];
    }
    for(int i=0;i<n;i++){
        cin>>in[i];
        pos[in[i]] = i;
    }
    build(0,n-1,0,n-1);

    bfs(post[n-1]);
    cout<<endl;
    
    
}




3、有向无环图的最深的根⭐

先判断连通性—并查集;也可以用dfs。 #并查集
已知连通,判断是否是树-----n个节点的树最多有n-1条边
最后暴力枚举每个节点进行dfs求深度。
1021 Deepest Root

#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int N = 1e4+10,M=2*N;

int p[N];

int head[N],val[M],ne[M];
int idx=0;

void add(int a,int b){
    val[idx] = b;
    ne[idx] =head[a];
    head[a] = idx++;
}

int find(int x){
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}

int visited[N];
int dfs(int v){
    int depth=0;
    visited[v]=1;
    for(int idxx=head[v];idxx!=-1;idxx=ne[idxx]){
        int child = val[idxx];
        if(!visited[child])
        depth = max(depth,dfs(child) +1);
    }
    return depth;
}

int main (){
    memset(head,-1, sizeof head);
    int n;cin>>n;int k=n;
    for(int i=1;i<=n;i++) p[i]=i;
    for(int i=0;i<n-1;i++){
        int a,b;cin>>a>>b;
        add(a,b);add(b,a);
        if(find(a)!=find(b))
        p[find(a)]=find(b),
        k--;
    }
    if(k>1) cout<<"Error: "<<k<<" components";
    else{
        int max_depth =-1;
        vector<int> ans;
        for(int v=1;v<=n;v++){
            int depth =dfs(v);
            memset(visited,0,sizeof visited);
            if(depth > max_depth) max_depth =depth,ans.clear(),ans.push_back(v);
            else if(depth == max_depth) ans.push_back(v);
        }

        for(auto &node:ans){
            cout<<node<<endl;
        }
    }




}
4、判断二叉搜索树⭐

题目:给前序遍历,判断是否是二叉搜索树,并输出后序遍历。
这个得到后序遍历的结果的太牛了。
post[cnt++]=root;
1043 Is It a Binary Search Tree #二叉搜索树的中序遍历是递增的。 #根据前序中序得后序

#include<iostream>
#include<cstring>
#include<vector>
using    namespace std;
const int N = 1000+10,M=2*N;
int pre[N],post[N],cnt;


bool isbin(int begin,int end){
    if(end < begin) return true;
    int root = pre[begin];

    int i=begin+1;
    for(;i<=end;i++){
        if(pre[i]>=root) break;
    }
    int le=i-1;
    int rb=i;
    for(;i<=end;i++){
        if(pre[i]<root) return false; 
    }
    int ans = true;
    if(!isbin(begin+1,le) ) ans=false;
    if(!isbin(rb,end) )   ans = false;
    post[cnt++] = root;
    return  ans ;
}

bool ismir(int begin,int end){
    if(end<begin) return true;
    int root = pre[begin];

    int i=begin+1;
    for(;i<=end;i++){
        if(pre[i]<root) break;
    }
    int le=i-1;
    int rb=i;
    for(;i<=end;i++){
        if(pre[i]>=root) return false; 
    }
    int ans = true;
    if(!ismir(begin+1,le) ) ans=false;
    if(!ismir(rb,end) )   ans = false;
    post[cnt++] = root;
    return  ans ;
}



int main(){
    int n;cin>>n;
    for(int i=0;i<n;i++){
        cin>>pre[i];
    }
    if(isbin(0,n-1)) {
        cout<<"YES"<<endl;
        cout<<post[0];
        for(int i=1;i<n;i++){
            cout<<" "<<post[i];
        }
    }
    else if( cnt=0,ismir(0,n-1) ){
        cout<<"YES"<<endl;
        cout<<post[0];
        for(int i=1;i<n;i++){
            cout<<" "<<post[i];
        }
    }

    else cout<<"NO"<<endl;







    
}
5、完全二叉搜索树✔

中序遍历一下,递增的把点填进树里就行。
1064 Complete Binary Search Tree #完全二叉树用一维数组表示

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1000+10;
int tree[N],order[N],cnt;
int n;

void solve(int v){
    if(2*v<=n) solve(2*v);
    tree[v] = order[cnt++];
    if(2*v+1<=n) solve(2*v+1);
}

int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>order[i];
    }
    sort(order,order+n);

    solve(1);

    cout<<tree[1];
    for(int i=2;i<=n;i++){
        cout<<" "<<tree[i];
    }
    cout<<endl;
}
6、非递归后序遍历✔

a.一般是改堆栈方式:如果右孩子没有被访问过或者没有右孩子,则出栈并输出。145. 二叉树的后序遍历
b.这题的堆栈方式给定了,可以等到先序和中序,可再推后序。(柳佬也是这么做的,背模板的话应该也不是太耗时间吧?)
c.或者用y总的方式。
1086 Tree Traversals Again #根据前序中序得后序


7、给顶结构的二叉搜索树✔

与第5题类似
1099 Build A Binary Search Tree #二叉搜索树的中序遍历是递增的。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 100+10,M = 2*N;
int inorder[N],cnt;
int l[N],r[N];
int tree[N];

void dfs(int v){
    if(l[v]!=-1) dfs(l[v]);
    tree[v] = inorder[cnt++];
    if(r[v]!=-1) dfs(r[v]);
}

queue<int> Q;
void bfs(int root){
    Q.push(root);cout<<tree[root];
    while(!Q.empty()){
        int v=Q.front();Q.pop();
        if(l[v]!=-1){Q.push(l[v]);cout<<" "<<tree[l[v]];}
        if(r[v]!=-1){Q.push(r[v]);cout<<" "<<tree[r[v]];}
    }
}

int main(){
    int n;cin>>n;
    for(int i=0;i<n;i++){
        cin>>l[i]>>r[i];    
    }
    for(int i=0;i<n;i++){
        cin>>inorder[i];
    }
    sort(inorder,inorder+n);
    dfs(0);

    bfs(0);
    cout<<endl;
}
8、反转二叉树✔

1102 Invert a Binary Tree

#include<iostream>
#include<cstring>
#include<queue>

using namespace std;
const int N = 30;
int l[N],r[N];
int tree[N];
int inorder[N],cnt;
int isroot[N];
queue<int> Q;
void bfs(int root){
    Q.push(root);cout<<root;
    while(!Q.empty()){
        int v = Q.front();Q.pop();
        if(l[v]!=-1) Q.push(l[v]),cout<<" "<<l[v];
        if(r[v]!=-1) Q.push(r[v]),cout<<" "<<r[v];
    }
}

void dfs(int v){
    if(l[v]!=-1) dfs(l[v]);
    inorder[cnt++]=v;
    if(r[v]!=-1) dfs(r[v]);
    
}

int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        string a,b;
        cin>>a>>b;
        if(a[0]=='-') r[i]=-1;
        else r[i]=a[0]-'0',isroot[r[i]] = 1;
        if(b[0]=='-') l[i]=-1;
        else l[i]=b[0]-'0',isroot[l[i]] = 1;
    }

    int root;
    for(int i=0;i<n;i++) {
        if(isroot[i]==0) root =i;}
    
    bfs(root);
    cout<<endl;
    dfs(root);

    cout<<inorder[0];
    for(int i=1;i<n;i++){
        cout<<" "<<inorder[i];
    }
    cout<<endl;
}

9、判断完全二叉树✔

数据读入有问题处理了2个小时,人麻了。
因为第8题的n是小于10的,lc[0]不能读2位数。
1110 Complete Binary Tree #完全二叉树用一维数组表示

#include<iostream>
#include<cstring>
using namespace std;
const int N = 20;
int l[N],r[N];
int isroot[N];
int tree[N];
int main(){
    int n;cin>>n;
        memset(l, -1, sizeof l);
    memset(r, -1, sizeof r);
    string ls, rs;
    for (int i = 0; i < n; i++) {
        cin >> ls >> rs;
        if (ls != "-") {
            l[i] = stoi(ls);
            isroot[l[i]] = 1;
        }
        if (rs != "-") {
            r[i] = stoi(rs);
            isroot[r[i]] = 1;
        }
    }

    int root=0;
    for(int i=0;i<n;i++){
        if(isroot[i]==0) root=i;
    }

    memset(tree,-1,sizeof tree);
    tree[1]=root;
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(tree[i]==-1) continue;
        tree[2*i] = l[tree[i]];
        tree[2*i+1] = r[tree[i]];
        cnt++;
    }

if(cnt==n) cout<<"YES "<<tree[n]<<endl;
else cout<<"NO "<<root<<endl;
    
}
10、二叉搜索树的插入✔

1115 Counting Nodes in a Binary Search Tree

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1000+10;
int l[N], r[N],val[N];
int cnt;
int high[N];
void insert(int i,int root){
    if(val[i]<=val[root]) {
         if(l[root]==-1) l[root]=i;   
         else insert(i,l[root]);
    }
    if(val[i]>val[root] ){
        if(r[root]==-1) r[root]=i;   
        else insert(i,r[root]);
    }
}
queue<int> Q;
void bfs(int root){
    Q.push(root);
    while(!Q.empty()){
        int n = Q.size();

        for(int i=0;i<n;i++){
            int v= Q.front();Q.pop();
            high[cnt]++;
            if(l[v]!=-1) Q.push(l[v]); 
            if(r[v]!=-1) Q.push(r[v]);
        }
        cnt++;
    }
}

int main(){
    int n;cin>>n;
    memset(l,-1,sizeof l);
    memset(r,-1,sizeof r);
    for(int i=0;i<n;i++) cin>>val[i];//insert(i,0);
    for(int i=1;i<n;i++) insert(i,0);

    bfs(0);
    cout<<high[cnt-1]<<" + "<<high[cnt-2]<<" = "<<high[cnt-1]+high[cnt-2];
}
11、前序后序得中序✔

y总是暴力枚举的,我觉得不太行。
按我的来吧
1119 Pre- and Post-order Traversals #根据前序中序得后序

#include<iostream>
#include<cstring>
using namespace std;
const int N = 40;

int pre[N],post[N];
int pos[N];
int inorder[N],idx;
int dfs(int l1,int r1,int l2,int r2){
    if(l1 > r1 ) return 1;
    if(l1==r1) {
            inorder[idx++]=pre[l1];
        return 1;
    }
    int flag=0;
    if(pre[l1+1]==post[r2-1]) flag=1;
    
    int cnt = 0;
    int length = pos[pre[l1+1]] -l2 +1;
    
    int lcnt = dfs(l1+1,l1+1+length-1,l2,l2+length-1);
    inorder[idx++]=pre[l1];
    int rcnt =dfs(l1+1+length,r1,l1+1+length-r1+r2-1,r2-1);

    cnt = lcnt*rcnt;
    if(flag==1) cnt=2*cnt;
    
    return cnt;
    
}


int main(){
    int n;cin>>n;
    for(int i=0;i<n;i++) cin>>pre[i];
    for(int i=0;i<n;i++) cin>>post[i],pos[post[i]]=i;

    
    int cnt = dfs(0,n-1,0,n-1);

    if(cnt==1) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;

    cout<<inorder[0];
    for(int i=1;i<n;i++){
        cout<<" "<<inorder[i];
    }
    cout<<endl;

    
}
12、Z型层序遍历✔

1127 ZigZagging on a Tree #根据前序中序得后序

#include<iostream>
#include<cstring>
#include<unordered_map>
#include<queue>
using namespace std;
const int N = 40;

int inorder[N],post[N];
unordered_map<int,int> l,r,pos; 
int lorder[N],cnt;

int build(int il,int ir,int pl,int pr){
    int root = post[pr];
    int k = pos[root];

    if(il<k) l[root] = build(il,k-1,pl,k-1-il+pl);
    if(k<ir) r[root] = build(k+1,ir, k+1-ir+pr-1 ,pr-1);
        return root;
}

queue<int> Q;
void bfs(int root){
    int level=0;
    Q.push(root);
    while(!Q.empty()){
        int n=Q.size();
        for(int i=0;i<n;i++){
            int v= Q.front();Q.pop();
            if(level % 2== 0)
               lorder[cnt+n-1-i] = v;
            else lorder[cnt+i] = v;
            if(l.count(v)) Q.push(l[v]);
            if(r.count(v)) Q.push(r[v]);
        }
        cnt+=n;
        level++;
    }
}

int main(){
    int n;cin>>n;
    for(int i=0;i<n;i++) cin>>inorder[i],pos[inorder[i]]=i;
    for(int i=0;i<n;i++) cin>>post[i];

    int root = build(0,n-1,0,n-1);

    bfs(root);
    cout<<lorder[0];
    for(int i=1;i<n;i++) cout<<" "<<lorder[i];
    cout<<endl;
}
13、前序中序得后序第一位✔

这题主要增大了N,必须用hash存pos。
1138 Postorder Traversal #根据前序中序得后序

#include<iostream>
#include<unordered_map>

using namespace std;

const int N= 50010;

int pre[N],inorder[N];
unordered_map<int,int> l,r,pos;
int post[N],cnt;
int ans;

void build(int pl,int pr,int il,int ir){
    int root = pre[pl];
    int k = pos[root];

    if(k > il) build( pl+1,k-1-il+pl+1 ,il,k-1); 
    if(k< ir) build(    k+1-ir+pr,pr,k+1,ir); 

   // post[cnt++]=root;
    if(!cnt++) ans=root;
}

int main(){
    int n;cin>>n;
    for(int i=0;i<n;i++) cin>>pre[i];
    for(int i=0;i<n;i++) cin>>inorder[i],pos[inorder[i]]=i;

    build(0,n-1,0,n-1);

      //  cout<<post[0]<<endl;
    cout<<ans<<endl;
}
14、平衡二叉树的插入✔

y总那个太复杂了,可能我没get到吧
按我的来吧。
1066 Root of AVL Tree

#include<iostream>
//#include<algorithm>
#include<cstring>
#include<unordered_map>
using namespace std;
const int N = 30;

int l[N],r[N],val[N];

unordered_map<int,int> high;//初始化是0
void update(int u){
   high[u] = max(high[l[u]],high[r[u]])+1;
}

void R(int &a){
   int b = l[a];
   l[a] = r[b],r[b] = a;
   update(a),update(b);
   a = b;
}

void L(int &a){
   int b = r[a];
   r[a] = l[b],l[b] = a;
   update(a),update(b);
   a = b;
}

int get_balance(int u){
   return high[l[u]] - high[r[u]];
}


void insert(int i,int &root){
   if(val[i]<val[root]){
       if(l[root]==-1) l[root]=i,high[i]=1;
       else insert(i,l[root]);
       if(get_balance(root) ==2 ){
           if(get_balance(l[root])==1) R(root);
           else L(l[root]),R(root);
       }
   }
   else{
       if(r[root]==-1) r[root]=i,high[i]=1;
       else insert(i,r[root]);
       if(get_balance(root) ==-2 ){
           if(get_balance(r[root])==-1) L(root);
           else R(r[root]),L(root);
       }
   }
   update(root);
}


int main (){
   high[-1]=0;
   int n;cin>>n;
   memset(l,-1,sizeof l);
   memset(r,-1,sizeof r);
   for(int i =0;i<n;i++)   cin>>val[i];
   int root=0;high[0]=1;
   for(int i =1;i<n;i++) insert(i,root);

   cout<<val[root];
}
15、平衡二叉树的插入plus✔

AVL的插入;层序遍历;判断完全二叉树。
1123 Is It a Complete AVL Tree

#include<iostream>
#include<unordered_map>
#include<cstring>
#include<queue>

using namespace std;
const int N = 30;

int l[N],r[N],val[N];
unordered_map <int,int> high;

void update(int i){
    high[i] = max(high[l[i]],high[r[i]])+1;
}

int get_balance(int u){
    return high[l[u]]-high[r[u]];
}

void R(int &a){
    int b = l[a];
    l[a] = r[b];
    r[b] = a;
    update(a),update(b);
    a = b;
}

void L(int &a){
    int b = r[a];
    r[a] = l[b];
    l[b] = a;
    update(a),update(b);
    a = b;
}

void insert(int i,int &root){
    if(val[i]<val[root]){
        if(l[root]==-1) l[root]=i,high[i]=1;
        else {
            insert(i,l[root]);
            if(get_balance(root)==2){
                if(get_balance(l[root])==1) R(root);
                else L(l[root]),R(root);
            }
        }
    }
    else if(val[i]>val[root]){
        if(r[root]==-1) r[root]=i,high[i]=1;
        else {
            insert(i,r[root]);
            if(get_balance(root)==-2){
                if(get_balance(r[root])==-1) L(root);
                else R(r[root]),L(root);
            }
        }
    }

    update(root);
}

queue<int> Q;
void bfs(int root){
    Q.push(root);cout<<val[root];
    while(!Q.empty()){
        int v = Q.front();Q.pop();
        if(l[v]!=-1) Q.push(l[v]),cout<<" "<<val[l[v]];
        if(r[v]!=-1) Q.push(r[v]),cout<<" "<<val[r[v]];
    }
}

int max_k;
void dfs(int i,int k){
    max_k=max(max_k,k);
    if(l[i]!=-1) dfs(l[i],2*k);
    if(r[i]!=-1) dfs(r[i],2*k+1);
}

int main(){
    high[-1]=0;
    memset(l,-1,sizeof l);
    memset(r,-1,sizeof r);
    int n;cin>>n;
    for(int i=0;i<n;i++) cin>>val[i];
    int root=0;high[0]=1;
    for(int i=1;i<n;i++) insert(i,root);

    bfs(root);

    dfs(root,1);
    if(max_k>n) cout<<endl<<"NO"<<endl;
    else cout<<endl<<"YES"<<endl;
    
}
16、判断红黑树✔

1135 Is It A Red-Black Tree #二叉搜索树的中序遍历是递增的。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<unordered_map> 
using namespace std;

const int N = 40;
int pre[N],inorder[N];
unordered_map<int,int> pos,l,r;

bool ans;


bool cmp(int a,int b){
    return abs(a)<abs(b);
}

int build(int pl,int pr,int il,int ir,int &sum){
    //if(pl > pr) return -1;
    int root = pre[pl];
    int k = pos[root];

    if( k <il || k>ir){
        ans = false;
        return 0;
    }
// 给定的前序遍历非法。
// 1
// 9
// 7 -2 1 5 -4 -11 3 14 -15
    
    int ls=0,rs=0;
    if(il < k ) l[root] = build(pl+1,k-1-il+pl+1 ,    il,k-1,ls);
    if( k < ir)  r[root] = build(  k+1-ir+pr     ,pr,k+1,ir,rs);

    if(ls!=rs) ans=false;  //左右子树黑结点个数不等
    sum = ls;
    if(root < 0) {
        if(l[root] <0 || r[root] <0) ans=false;   //红色结点的孩子也是红色结点 则 非法。
    }
    else sum++;     //黑结点个数+1

    
    return root;
}



int main(){
    int k;cin>>k;
    while(k--){
        l.clear();
        r.clear();
        pos.clear();
        int n;cin>>n;
        for(int i=0;i<n;i++) cin>>pre[i],inorder[i]=pre[i];
        sort(inorder,inorder+n,cmp);
        for(int i=0;i<n;i++) pos[inorder[i]]=i;
        int sum=0;
        ans = true;
        int root = build(0,n-1,0,n-1,sum);


        if( ans && root>0) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    
}

17、路径之和✔

每次dfs前后 对自己需要的内容进行处理,有点回溯那味了。
1053 Path of Equal Weight

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

const int N = 110;
int head[N],val[N],ne[N],idx=0;
int w[N];
int tag;
vector<int> path;
vector< vector <int> > ans;
int sum=0;

void add(int a,int b){
    val[idx] = b;
    ne[idx] = head[a];
    head[a] = idx++;
}

void dfs(int root){
    path.push_back(w[root]);sum+=w[root];
    if(sum==tag && head[root]==-1 ) ans.push_back(path);
    for(int idxx=head[root];idxx!=-1;idxx=ne[idxx]){
        dfs(val[idxx]);
    }
    path.pop_back();
    sum-=w[root];
    
}

int main(){
    memset(head,-1,sizeof head);
    int n,m;
    cin>>n>>m>>tag;
    for(int i=0;i<n;i++) cin>>w[i];
    for(int i=0;i<m;i++){
        int v;cin>>v;
        int k;cin>>k;
        while(k--){
            int b;cin>>b;
            add(v,b);
        }
    }

    dfs(0);
    sort(ans.begin(),ans.end());
    reverse(ans.begin(),ans.end());
    for(auto &v : ans){
        cout<<v[0];
        for(int i=1;i<v.size();i++){
            cout<<" "<<v[i];
        }
        cout<<endl;
    }
}
18、最大层数✔

1094 The Largest Generation

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;

const int N = 110;
int head[N],ne[N],val[N],idx=0;

void add(int a,int b){
    val[idx] = b;
    ne[idx] = head[a];
    head[a] = idx++;
}

int max_level,max_cnt;
queue<int> Q;
void bfs(int root){
    Q.push(root);
    int level=0;
    while(!Q.empty()){
        int n=Q.size();
        level++;
        if(n>max_cnt) {
            max_cnt =n;
            max_level = level;
        }
        for(int i=0;i<n;i++){
            int v = Q.front();Q.pop();
            for(int idxx=head[v];idxx!=-1;idxx=ne[idxx]){
                int child = val[idxx];
                Q.push(child);
            }
        }
    }
}


int main(){
    memset(head,-1,sizeof head);
    int n,m;cin>>n>>m;
    while(m--){
        int v,k;cin>>v>>k;
        while(k--) {
            int b;cin>>b;
            add(v,b);
        }
    }

    bfs(1);
    cout<<max_cnt<<" "<<max_level<<endl;
}
19、供应链1✔

1079 Total Sales of Supply Chain

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;

const int N = 1e5+10;
int head[N],val[N],ne[N],idx=0;
int sales[N];
double rate,price;
double ans=0;

void add(int a,int b){
    val[idx] = b;
    ne[idx] = head[a];
    head[a] = idx++;
}

queue<int> Q;
void bfs(int root){
    Q.push(root);
    while(!Q.empty()){
        int n=Q.size();
        while(n--){
            int v = Q.front();Q.pop();
            if(sales[v]>0) ans+=sales[v]*price;//cout<<price<<" ";
            for(int idxx=head[v];idxx!=-1;idxx=ne[idxx]){
                int child = val[idxx];
                Q.push(child);
            }
        }
        price *= (1+rate/100);
    }
}

int main(){
    memset(head,-1,sizeof head);
    int n;
    cin>>n>>price>>rate;
    for(int i=0;i<n;i++){
        int k;cin>>k;
        if(k>0) {
            while(k--){
                int b;cin>>b;add(i,b);
            }
        }
        else cin>>sales[i];
    }
    bfs(0);
    printf("%.1lf\n",ans);
}
20、供应链2✔

1090 Highest Price in Supply Chain

#include<iostream>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;

const int N = 1e5+10;

int head[N],val[N],ne[N],idx=0;
double price,rate;

void add(int a,int b){
    val[idx] = b;
    ne[idx] = head[a];
    head[a] =idx++;
}

int level,cnt;

queue<int> Q;
void bfs(int root){
    Q.push(root);
    while(!Q.empty()){
        int n=Q.size();level++;
        cnt=n;
        while(n--){
            int v=Q.front();Q.pop();
            for(int idxx=head[v];idxx!=-1;idxx=ne[idxx]){
                int child = val[idxx];
                Q.push(child);
            }
        }
    }
}

int main(){
    memset(head,-1,sizeof head);
    int n;cin>>n>>price>>rate;
    int root=-1;
    for(int i=0;i<n;i++){
        int a;cin>>a;
        if(a!=-1) add(a,i);
        else root=i;
    }

    bfs(root);

    printf("%.2lf %d\n",price*pow((1+rate/100),level-1),cnt);
}
21、供应链3✔

1106 Lowest Price in Supply Chain


22、堆路径

1155 Heap Paths

23、

1130 Infix Expression

24、

1143 Lowest Common Ancestor

25、

1151 LCA in a Binary Tree


并查集

1、战争中的城市连通✔

合并的操作!!! -------> p【find(a)】=find(b)
1013 Battle Over Cities #并查集

#include<iostream>
#include<vector>
#include<map>
using namespace std;
typedef pair<int,int> PII;

const int N = 1000+10,M=N*N;
int n,m;
int d[N][N];    //距离矩阵初始化
int p[N];    //并查集
PII edge[M];


int find(int x){
    if(p[x] !=x ) p[x]=find(p[x]);
    return p[x];
}



void count_connect(int id){
    for(int i=1;i<=n;i++) p[i]=i; //初始化
    for(int i=0;i<m;i++){
        int a=edge[i].first;
        int b= edge[i].second;
        if(a!=id && b!=id &&  find(a)!=find(b)) p[find(a)]=find(b);
    }
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(p[i]==i) cnt++;
    }
    cout<<cnt-2<<endl;
}

int main()
{
    int k;
    cin>>n>>m>>k;  
    for(int i=0;i<m;i++){
        int pos1,pos2;
        cin>>pos1>>pos2;
        edge[i].first=pos1;
        edge[i].second=pos2;
    }           //完成距离矩阵赋值
    
    
    while(k--){
        int city_id;
        cin>>city_id;
        count_connect(city_id);   //连通图,去掉这个city相关路径后,还剩的连通个数(遍历)
    }

}
2、房产⭐

需要维护每个家庭的信息。
1114 Family Property #并查集

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair <int,int> PII;

struct Family{
    string id;
    int cnt;
    double num,area;

    bool operator < (Family x){
        if(area != x.area) return area>x.area;
        else return id<x.id;
    }
};

const int N = 10000+10,M=N*7+10;
int n;
int p[N],visited[N],people_cnt[N],estate_cnt[N],area[N],head[N];
PII edge[M];int m=0;

int find(int x){
    if(x!=p[x]) p[x] = find(p[x]);
    return p[x];
}

string solve(int x){
    x+=10000;
    return to_string(x).substr(1);
}

int main(){
    for(int i=0;i<=9999;i++) p[i]=i,people_cnt[i]=1,head[i]=i;
    cin>>n;
    while(n--){
        int id,father,mother,k;
        cin>>id>>father>>mother>>k;
        visited[id]=true;
        if(father !=-1) edge[m++] = {id,father},visited[father]=true;
        if(mother !=-1) edge[m++] = {id,mother},visited[mother]=true;
        while(k--){
            int child;cin>>child;
            edge[m++] = {id,child};
            visited[child] = true;
        }
        double a,b;
        cin>>a>>b;
        estate_cnt[id]=a;
        area[id]=b;
    }

    for(int i=0;i<m;i++){
        int a=edge[i].first;
        int b=edge[i].second;
        if(find(a)!=find(b)){
            people_cnt[find(b)] += people_cnt[find(a)];
            estate_cnt[find(b)] += estate_cnt[find(a)];
            area[find(b)] += area[find(a)];
            head[find(b)] = min (head[find(a)],head[find(b)]); 
            p[find(a)] = find(b);  //这个一定要放最后
        }

    }

    int cnt=0;
    vector<Family> ans;
    for(int id=0;id<=9999;id++){
        if(visited[id] && p[id]==id){
            cnt++;
            int num = people_cnt[id];
            double a = estate_cnt[id];
            double b = area[id];
            ans.push_back({solve(head[id]),num,a/num,b/num});
        }
    }

    sort(ans.begin(),ans.end());
    cout<<cnt<<endl;
    for(auto &v:ans){
        cout<<v.id<<" "<<v.cnt<<" ";
        printf("%.3lf %.3lf\n",v.num,v.area);
    }
    
    
}

3、树上的鸟✔

有了上题,这题就秒解了。
1118 Birds in Forest #并查集

#include<iostream>
using namespace std;
const int N = 10000+10;
int n;
int p[N];
bool visited[N];

int find(int x){
    if(x!=p[x]) p[x]=find(p[x]);
    return p[x];
}

int main(){
    for(int i=0;i<N;i++) p[i]=i;
    cin>>n;
    for(int i=0;i<n;i++){
        int k;cin>>k;
        int first;
        cin>>first;visited[first]=true;
        for(int j=1;j<k;j++){
            int a;cin>>a;
            if(find(a)!=find(first) ){
                p[find(a)] = find(first);
                visited[a] = true;
            }
        }
    }
    int tree=0,bird=0;
    for(int i=0;i<N;i++){
        if(p[i]==i && visited[i]) tree++;
        if(visited[i]) bird++;
    }
    cout<<tree<<" "<<bird<<endl;
    
    int q;cin>>q;
    while(q--){
        int a,b;
        cin>>a>>b;
        if(find(a)==find(b)) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
}
4、社会集群✔

有相同爱好的人聚类到一起。
1107 Social Clusters #并查集

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;


const int N = 1000+10;
int n;
int p[N],cnt[N];
vector<int> hobbys[N];

int find(int x){
    if(x!=p[x]) p[x]=find(p[x]);
    return p[x];
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++) p[i]=i,cnt[i]=1;

    for(int i=1;i<=n;i++){
        int k;cin>>k;
        char temp;cin>>temp;
        while(k--){
            int hobby;cin>>hobby;
            hobbys[hobby].push_back(i);
        }
    }

    for(int i=1;i<=1000;i++){
        if(!hobbys[i].empty() ){
            for(int j=1;j<hobbys[i].size();j++){
                if(find(hobbys[i][j])!= find(hobbys[i][0]) ){
                    cnt[find(hobbys[i][0])] += cnt[find(hobbys[i][j])];
                    p[find(hobbys[i][j])] = find( hobbys[i][0]   ) ;
                }
            }
        }
    }

    int ans_cnt=0;
    vector<int> ans;
    for(int i=1;i<=n;i++){
        if(p[i]==i) ans_cnt++;
        if(p[i]==i)  ans.push_back(cnt[i]);
    }
    cout<<ans_cnt<<endl;
    sort(ans.begin(),ans.end(),greater<int>());
    cout<<ans[0];
    for(int i=1;i<ans.size();i++) cout<<" "<<ans[i];
    cout<<endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值