PAT 树

列表

A1147 Heaps堆的判定
A1155 Heap Paths堆的判定
1098 Insertion or Heap Sort堆排序
1004 Counting Leaves数每层叶子节点
A1020 Tree Traversals树的遍历、DFS
A1021 Deepest Root树的遍历、树的深度、DFS
A1079 Total Sales of Supply Chain广义树
A1090 Highest Price in Supply Chain广义树
A1106 Lowest Price in Supply Chain广义树
A1094 The Largest Generation广义树
A1130 Infix Expression广义树
A1086 Tree Traversals Again
A1102 Invert a Binary Tree
A1053 Path of Equal Weight
A1064 Complete Binary Search Tree
A1043 Is It a Binary Search Tree
A1099 Build A Binary Search Tree
A1127 ZigZagging on a Tree
A1115 Counting Nodes in a BST
A1138 Postorder Traversal
A1110 Complete Binary Tree完全二叉树
A1143 Lowest Common AncestorLCA
A1151 LCA in a Binary TreeLCA
A1107 Social Clusters并查集
A1118 Birds in Forest并查集
A1034 Head of a Gang并查集
A1114 Family Property并查集

A1147 堆 比1155简单

//简单
#include<stdio.h>
#include<vector>
#include<stdlib.h>
#include<algorithm> 
using namespace std;
vector<int>v1,v2,v3;
int n,m,temp,flag;
void downmaxAdjust(int low,int high){
    int i=low,j=i*2;
    while(j<=high){
        if(j+1<=high&&v2[j+1]>v2[j]){
            j=j+1;
        }
        if(v2[j]>v2[i]){
            swap(v2[i],v2[j]);
            i=j;
            j=i*2;
        }else break;
    }
}
void downminAdjust(int low,int high){
    int i=low,j=i*2;
    while(j<=high){
        if(j+1<=high&&v3[j+1]<v3[j]){
            j=j+1;
        }
        if(v3[j]<v3[i]){
            swap(v3[i],v3[j]);
            i=j;
            j=i*2;
        }else break;
    }
}
void Createmaxheap(){
    for(int i=m/2;i>=1;i--){
        downmaxAdjust(i,m);
    }
}
void Createminheap(){
    for(int i=m/2;i>=1;i--){
        downminAdjust(i,m);
    }
}
void postorder(int root){
    if(root*2<=m)postorder(root*2);
    if(root*2+1<=m)postorder(root*2+1);
    printf("%d",v1[root]);
    flag++;
    if(flag!=m)printf(" ");
    else printf("\n");
}
int main()
{
//     freopen("input.txt","r",stdin);
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;i++){       //调试的时候把n写成3了后来忘了改
        v1.clear();
        flag=0;
        v1.push_back(-1);
        for(int j=0;j<m;j++){
            scanf("%d",&temp);
            v1.push_back(temp);
        }
        v2=v3=v1;
        Createmaxheap();
        Createminheap();
        if(v1==v2)printf("Max Heap\n");
        else if(v1==v3)printf("Min Heap\n");
        else printf("Not Heap\n");
        postorder(1);
//         printf("\n");
    }
    return 0;
}//函数 循环体意外进不去情况   原来是输入文件名写错了 

// 什么鬼 测试样例过了 测试点一个也不对。。。

A1155 堆 输出路径题

#include<stdio.h>
#include<vector>
#include<stdlib.h>
#include<algorithm>
using namespace std;
vector<int>v1,v2,v3;
int n,temp;
vector<int>path;
void maxdownAdjust(int low,int high){
    int i=low,j=i*2;
    while(j<=high){
        if(j+1<=high&&v2[j+1]>v2[j]){
            j=j+1;
        }
        if(v2[j]>v2[i]){
            swap(v2[j],v2[i]);
            i=j;
            j=i*2;
        }else break;
    }
}
void mindownAdjust(int low,int high){
    int i=low,j=i*2;
    while(j<=high){
        if(j+1<=high&&v3[j+1]<v3[j]){
            j=j+1;
        }
        if(v3[j]<v3[i]){
            swap(v3[j],v3[i]);
            i=j;
            j=i*2;
        }else break;
    }
}
void createmaxheap(){
    for(int i=n/2;i>=1;i--){
        maxdownAdjust(i,n);
    }
}
void createminheap(){
    for(int i=n/2;i>=1;i--){
        mindownAdjust(i,n);
    }
}
int flag=0;
void DFS(int root){
    if(root*2>n){
        path.push_back(v1[root]);
        for(int i=0;i<path.size();i++){
            printf("%d",path[i]);
            if(i!=path.size()-1)printf(" ");
        }
        printf("\n");
        path.pop_back();
        return;
    }
    path.push_back(v1[root]);
    if(root*2+1<=n)DFS(root*2+1);
    DFS(root*2);
    path.pop_back();
}
int main()
{
// 	freopen("input.txt","r",stdin);
    scanf("%d",&n);
    v1.push_back(-1);
    for(int i=0;i<n;i++){
        scanf("%d",&temp);
        v1.push_back(temp);
    }
    v2=v3=v1;
    createmaxheap();
    createminheap();
    DFS(1);
    if(v1==v2)printf("Max Heap\n");
    else if(v1==v3)printf("Min Heap\n");
    else printf("Not Heap\n");
    return 0;
}

路径输出题 两个向下调整 两个建堆 判断是最大堆或是最小堆在DFS输出路径

A1098 堆排序

#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
int n;
void downAdjust(vector<int> &b,int low,int high){
    int i=low,j=1*2;
    while(j<=high){
        if(j+1<=high&&b[j+1]>b[j]){
            j=j+1;
        }
        if(b[j]>b[i]){
            swap(b[j],b[i]);
            i=j;
            j=i*2;
        }
    }
}
int main()
{
    scanf("%d",&n);
    vector<int>a(n+1),b(n+1),c(n+1);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)scanf("%d",&b[i]);   
    c=a;
    int flag=0;
    for(int i=2;i<=n;i++){
        sort(c.begin()+1,c.begin()+1+i);
        if(c==b){
            flag=1;
            printf("Insertion Sort\n");
            sort(c.begin(),c.begin()+2+i);
            for(int j=1;j<=n;j++){
                printf("%d",c[j]);
                if(j!=n)printf(" ");
            }
            break;
        }
    }
    if(flag==0){
        printf("Heap Sort\n");
        sort(c.begin(),c.end());
        int i;
        for(i=n;i>=1;i--){
            if(c[i]!=b[i])break;
        }
        swap(b[1],b[i]);
        downAdjust(b,1,i-1);
        for(i=1;i<=n;i++){
            printf("%d",b[i]);
            if(i!=n)printf(" ");
        }
    }
}

如果不是插入排序就是堆排序,判断堆排序排序点的位置从后往前判断

A1020 前中序构建二叉树 简单

#include<stdio.h>
#include<queue>
using namespace std;
struct node{
    int data;
    node* lchild;
    node* rchild;
};
const int maxn=50;
int n;
int post[maxn],in[maxn];
int num=0;
node* create(int postl,int postr,int inl,int inr){
    if(postl>postr){
        return NULL;
    }
    node* root=new node;
    root->data=post[postr];
    int k;
    for(k=inl;k<=inr;k++){
        if(in[k]==post[postr])break;
    }
    int numleft=k-inl;
    root->lchild=create(postl,postl+numleft-1,inl,k-1);
    root->rchild=create(postl+numleft,postr-1,k+1,inr);
    return root;
}
void Layerorder(node* root){
    queue<node*>q;
    q.push(root);
    while(!q.empty()){
        node* front=q.front();
        q.pop();
        printf("%d",front->data);
        num++;
        if(num!=n)printf(" ");
        if(front->lchild!=NULL)q.push(front->lchild);
        if(front->rchild!=NULL)q.push(front->rchild);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&post[i]);
    }
    for(int i=0;i<n;i++){
        scanf("%d",&in[i]);
    }
    node* root=create(0,n-1,0,n-1);
    Layerorder(root);
    return 0;
}

A1021 最深节点 图题 难

A1079 零售商 算总价

#include<stdio.h>
#include<vector>
#include<math.h>
using namespace std;
const int maxn=100010;
struct node{
    int data;
    vector<int>child;
}Node[maxn];
int n;
double p,r,num=0.0;
int m,temp1;
void DFS(int root,int index){
    if(Node[root].child.size()==0){
        num+=Node[root].data*pow(1+r,index)*p;
        return;
    }
    for(int i=0;i<Node[root].child.size();i++){
        DFS(Node[root].child[i],index+1);
    }
}
int main()
{
    scanf("%d %lf %lf",&n,&p,&r);
    r/=100.0;
    for(int i=0;i<n;i++){
        scanf("%d",&m);
        if(m!=0){
            for(int j=0;j<m;j++){
                scanf("%d",&temp1);
                Node[i].child.push_back(temp1);
            }
        }else {
            scanf("%d",&Node[i].data);
        }
    }
    DFS(0,0);
    printf("%.1lf\n",num);
    return 0;
}

简单题,r记得除100

A1090 经销商问题 求最深节点深度、个数

Sroot for the root supplier is defined to be −1. 读题

注意一下输入找根节点。

#include<stdio.h>
#include<math.h>
#include<vector>
using namespace std;
const int maxn=100010;
vector<int>child[maxn];
double p,r;
int n,maxdepth=0,num=0;
void dfs(int index,int depth){
    if(child[index].size()==0){
        if(depth>maxdepth){
            maxdepth=depth;
            num=1;
        }
        else if(depth==maxdepth){
            num++;
        }
        return;
    }
    for(int i=0;i<child[index].size();i++){
        dfs(child[index][i],depth+1);
    }
}
int main()
{
    scanf("%d %lf %lf",&n,&p,&r);
    r/=100;
    int father,root;
    for(int i=0;i<n;i++){
        scanf("%d",&father);
        if(father!=-1){
            child[father].push_back(i);
        }
        else{
            root=i;
        }
    }
    dfs(root,0);
    printf("%.2lf %d\n",p*pow(r+1,maxdepth),num);
    return 0;
}

A1106 经销商 求最浅节点层次及个数 简单

#include<stdio.h>
#include<vector>
#include<math.h>
using namespace std;
const int maxn=100010;
vector<int>child[maxn];
int n,mindepth=maxn,sum=0;
double p,r;
void dfs(int index,int depth){
    if(child[index].size()==0){
        if(depth<mindepth){
            mindepth=depth;
            sum=1;
        }
        else if(depth==mindepth){
            sum++;
        }
        return;
    }
    for(int i=0;i<child[index].size();i++){
        dfs(child[index][i],depth+1);
    }
}
int main()
{
    scanf("%d %lf %lf",&n,&p,&r);
    r/=100;
    int n2,child2;
    for(int i=0;i<n;i++){
        scanf("%d",&n2);
        for(int j=0;j<n2;j++){
            scanf("%d",&child2);
            child[i].push_back(child2);
        }
    }
    dfs(0,0);              
    printf("%.4lf %d",p*pow(r+1,mindepth),sum);
    return 0;
}

A1094 家族谱 求节点最多的层 及个数 简单

#include<stdio.h>
#include<vector>
using namespace std;
const int maxn=100010;
vector<int>child[maxn];
int layer[maxn]={0};
void dfs(int index,int depth){
    layer[depth]++;
    for(int i=0;i<child[index].size();i++){
        dfs(child[index][i],depth+1);
    }
}
int main()
{
    int n,m,child1,n2,child2;
    scanf("%d %d",&n,&m);
    for(int i=0;i<m;i++){
        scanf("%d %d",&child1,&n2);
        for(int j=0;j<n2;j++){
            scanf("%d",&child2);
            child[child1].push_back(child2);
        }
    }
    dfs(1,1);
    int max=0,maxq=0;
    for(int i=0;i<maxn;i++){
        if(layer[i]>max){
            max=layer[i];
            maxq=i;
        }
    }
    printf("%d %d\n",max,maxq);
    
    return 0;
}

1004 家族谱 求每层叶子节点个数 简单

#include<stdio.h>
#include<vector>
using namespace std;
const int maxn=100010;
vector<int>child[maxn];
int layer[maxn]={0};
int maxdepth=0;
void dfs(int index,int depth){
    if(child[index].size()==0){
        layer[depth]++;
        if(depth>maxdepth){
            maxdepth=depth;
        }
    }
    for(int i=0;i<child[index].size();i++){
        dfs(child[index][i],depth+1);
    }
}
int main()
{
    int n1,m,father,n2,child2;
    scanf("%d %d",&n1,&m);
    for(int i=0;i<m;i++){
        scanf("%d %d",&father,&n2);
        for(int j=0;j<n2;j++){
            scanf("%d",&child2);
            child[father].push_back(child2);
        }
    }
    dfs(1,1);
    printf("%d",layer[1]);
    for(int i=2;i<=maxdepth;i++){
        printf(" %d",layer[i]);
    }
    return 0;
}

注意在DFS的时候就把最深层层数求出来

A1130 二叉树输出中缀表达式

#include<stdio.h>
#include<string>
#include<stdlib.h>
#include<iostream>
using namespace std;
const int maxn=25;
struct node{
    string str;
    int lchild,rchild;
}Node[maxn];
int isroot[maxn]={0};
int n;
void inorder(int root){
    if(root==-1)return;
    int a=Node[root].lchild,b=Node[root].rchild;
    if(Node[a].lchild>=1||Node[a].rchild>=1)printf("(");
    inorder(Node[root].lchild);
    if(Node[a].lchild>=1||Node[a].rchild>=1)printf(")");
    cout<<Node[root].str;
    if(Node[b].lchild>=1||Node[b].rchild>=1)printf("(");
    inorder(Node[root].rchild);
    if(Node[b].lchild>=1||Node[b].rchild>=1)printf(")");
}
int main()
{
// 	freopen("input.txt","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        cin>>Node[i].str>>Node[i].lchild>>Node[i].rchild;
        if(Node[i].lchild!=-1)isroot[Node[i].lchild]=1;
        if(Node[i].rchild!=-1)isroot[Node[i].rchild]=1;
    }
    int root;
    for(int i=1;i<=n;i++){
        if(isroot[i]==0){
            root=i;
            break;
        }
    }
    inorder(root);
    return 0;
}

主要是输出括号比较麻烦,分别判断左右子树是否只有一个节点,如果大于1,在遍历前后输出括号。不知道为什么写!=-1不对

A1086 同1020 用栈输入

#include<iostream>
#include<stdio.h>
#include<stack>
#include<string>
using namespace std;
struct node{
    int data;
    node* lchild;
    node* rchild;
};
int pre[40],in[40],post[40];
stack<int>s;
node* Create(int preL,int preR,int inL,int inR){
    if(preL>preR){
        return NULL;
    }
    node* root=new node;
    root->data=pre[preL];
    int k;
    for(k=inL;k<=inR;k++){
        if(in[k]==pre[preL]){
            break;
        }
    }
    int numleft=k-inL;
    root->lchild=Create(preL+1,preL+numleft,inL,inL+numleft-1);
    root->rchild=Create(preL+numleft+1,preR,k+1,inR);         //这里的多一少一引发了全部段错误
    return root;
}
int k=0,n;
void postorder(node* root){
    if(root==NULL){
        return;
    }
    postorder(root->lchild);
    postorder(root->rchild);
    printf("%d",root->data);
    k++;
    if(k<n)printf(" ");
}
int main()
{
    int data1,i1=0,i2=0;
    scanf("%d",&n);
    string str;
    for(int i=0;i<2*n;i++){
        cin>>str;
        if(str=="Push"){
            cin>>data1;
             s.push(data1);
            pre[i1]=data1;
            i1++;
         //这里入栈顺序没有问题
        }
        else{
            in[i2]=s.top();
            i2++;
            s.pop();
        }
    }
    node* root=Create(0,n-1,0,n-1);
    postorder(root);
    return 0;
}

简单题,只不过换成了用栈输入。

A1102 静态二叉树遍历

#include<stdio.h>
#include<queue>
#include<iostream>
using namespace std;
const int maxn=12;
struct node{
    int lchild,rchild;
}Node[maxn];
int num=0;
int n;
int isroot[maxn]={0};
void Layerorder(int root){
    queue<int>q;
    q.push(root);
    while(!q.empty()){
        int now=q.front();
        q.pop();
        printf("%d",now);
        num++;
        if(num!=n)printf(" ");
        if(Node[now].lchild!=-1)q.push(Node[now].lchild);
        if(Node[now].rchild!=-1)q.push(Node[now].rchild);
    }
}
void inorder(int root){
    if(root==-1){
        return;
    }
    inorder(Node[root].lchild);
    printf("%d",root);
    num++;
    if(num!=n)printf(" ");
    inorder(Node[root].rchild);
}
int main()
{
    for(int i=0;i<maxn;i++){
        Node[i].lchild=Node[i].rchild=-1;
    }
    char a,b;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        cin>>a>>b;
        if(a!='-'){
            Node[i].rchild=a-'0';
            isroot[a-'0']=1;
        }
        if(b!='-'){
            Node[i].lchild=b-'0';
            isroot[b-'0']=1;
        }
    }
    int root0=-1;
    for(int i=0;i<n;i++){
        if(isroot[i]==0){
            root0=i;
            break;
        }
    }
    Layerorder(root0);
    printf("\n");
    num=0;
    inorder(root0);
    printf("\n");
    return 0;
}

用isroot[]数组来寻找根节点

A1053 输出多条路径 难

#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=100010;
struct node{
    int data;
    vector<int>children;
}child[maxn];
int n,m,s,lujing[maxn];
bool cmp(int a,int b){
    return child[a].data>child[b].data;
}
void dfs(int index,int sumnode, int sum){
    if(sum>s)return;
    if(sum==s){
        if(child[index].children.size()!=0)return;
        for(int i=0;i<sumnode-1;i++){
            printf("%d ",child[lujing[i]].data);
        }
        printf("%d\n",child[lujing[sumnode-1]].data);
        return ;
    }
    if(sum<s){
        for(int i=0;i<child[index].children.size();i++){
            lujing[sumnode]=child[index].children[i];
            dfs(child[index].children[i],sumnode+1,sum+child[child[index].children[i]].data);
        }//这里函数的递归用错了,参数调用的有错误
    }
}
int main()
{
    int n2,father,child2;
    scanf("%d %d %d",&n,&m,&s);
    for(int i=0;i<n;i++){
        scanf("%d",&child[i].data);
    }
    for(int i=0;i<m;i++){
        scanf("%d %d",&father,&n2);
        for(int j=0;j<n2;j++){
            scanf("%d",&child2);
            child[father].children.push_back(child2);
        }
        sort(child[father].children.begin(),child[father].children.end(),cmp);
    }
    lujing[0]=0;
    dfs(0,1,child[0].data);
    return 0;
}
//注意本题路径数组存储的结点的名字,而打印的是结点的data


//方法2
#include<stdio.h>
#include<algorithm>
#include<stdlib.h>
#include<vector>
using namespace std;
const int maxn=101;
struct node{
    int weight;
    vector<int>child;
}Node[maxn];
int n,m,s,fa,k,temp;
vector<int>temppath,path;
bool cmp(int a,int b){
	return Node[a].weight>Node[b].weight;
}
void DFS(int root){
    if(Node[root].child.size()==0){
//    	printf("*\n");
        temppath.push_back(root);
//        printf("&\n");
        int sum=0;
        for(int i=0;i<temppath.size();i++){
            sum+=Node[temppath[i]].weight;
//            printf("-------------%d\n",sum);
        }
        if(sum==s){
             for(int j=0;j<temppath.size();j++){
                 printf("%d",Node[temppath[j]].weight);
                 if(j!=temppath.size()-1)printf(" ");
             }
             printf("\n");
//            printf("9\n");
        }
        temppath.pop_back();
//        printf("%%\n");
        return;
    }
    temppath.push_back(root);
    for(int i=0;i<Node[root].child.size();i++){
        DFS(Node[root].child[i]);
    }
    temppath.pop_back();
}
int main()
{
// 	freopen("input.txt","r",stdin); 
    scanf("%d %d %d",&n,&m,&s);
    for(int i=0;i<n;i++){
        scanf("%d",&Node[i].weight);
    }
    for(int i=0;i<m;i++){
        scanf("%d %d",&fa,&k);
        for(int j=0;j<k;j++){
            scanf("%d",&temp);
            Node[fa].child.push_back(temp);
        }
        sort(Node[fa].child.begin(),Node[fa].child.end(),cmp);
    }
//    printf("%d\n",Node[Node[0].child[3]].weight);
    DFS(0);
    return 0;
}

第二种方法是根据图的Dijksta算法模板做出来的,调试了好久,刚开始计算sum的时候用编号累加的,后来sort函数在之前定义了cmp,sort里竟然忘写了。。。

sort的cmp函数也需要注意一下,挺特别的一个比较函数

A1064 构建完全二叉搜索树 难

#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=1010;
int n,in[maxn],a[maxn],num=1;
void inorder(int root){
    if(root>n){
        return;
    }
    inorder(root*2);
    in[root]=a[num++];
    inorder(root*2+1);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    sort(a+1,a+1+n);
    inorder(1);
    for(int i=1;i<=n;i++){
        printf("%d",in[i]);
        if(i!=n)printf(" ");
    }
    return 0;
}

完全二叉树一般都用数组来存储,二叉搜索树的中序遍历有顺序的

A1043 二茬搜索树 镜像遍历 简单

#include<stdio.h>
#include<vector>
using namespace std;
vector<int> temp,pre,prem,post,postm;
struct node{
    int data;
    node* lchild,*rchild;
};
void insert(node* &root,int x){
    if(root==NULL){
        root=new node;
        root->data=x;
        root->lchild=root->rchild=NULL;
        return;
    }
    if(x<root->data){
        insert(root->lchild,x);
    }
    else if(x>=root->data) {                             
        insert(root->rchild,x);                           
    }
}
void preorder(node* root){
    if(root==NULL)return;
    pre.push_back(root->data);
    preorder(root->lchild);
    preorder(root->rchild);
}
void premorder(node* root){
    if(root==NULL)return;
    prem.push_back(root->data);
    premorder(root->rchild);
    premorder(root->lchild);
}
void postorder(node* root){
    if(root==NULL)return;
    postorder(root->lchild);
    postorder(root->rchild);
    post.push_back(root->data);
}
void postmorder(node* root){
    if(root==NULL)return ;
    postmorder(root->rchild);
    postmorder(root->lchild);
    postm.push_back(root->data);
}
int main()
{
    int n,tempchild;
    scanf("%d",&n);
    node* root=NULL;
    for(int i=0;i<n;i++){
        scanf("%d",&tempchild);
        temp.push_back(tempchild);
        insert(root,tempchild);
    }
    preorder(root);
    premorder(root);
    postorder(root);
    postmorder(root);
    if(temp==pre){
        printf("YES\n");
        for(int i=0;i<post.size();i++){
            printf("%d",post[i]);
            if(i<post.size()-1)printf(" ");
        }
    }else if(temp==prem){
        printf("YES\n");
        for(int i=0;i<postm.size();i++){
            printf("%d",postm[i]);
            if(i<postm.size()-1)printf(" ");
        }
    }
    else {
        printf("NO\n");
    }
    return 0;
}

四种遍历各来一遍,都是树的基本操作

A1099 构建二叉搜索树 同1064

#include<stdio.h>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=110;
int n,in[maxn],num=0;
struct node{
    int data,lchild,rchild;
}Node[maxn];
void inorder(int root){
    if(root==-1)return;
    inorder(Node[root].lchild);
    Node[root].data=in[num++];
    inorder(Node[root].rchild);
}
void Layerorder(int root){
    queue<int>q;
    q.push(root);
    num=0;
    while(!q.empty()){
        int now=q.front();
        q.pop();
        printf("%d",Node[now].data);
        num++;
        if(num<n)printf(" ");
        if(Node[now].lchild!=-1)q.push(Node[now].lchild);
        if(Node[now].rchild!=-1)q.push(Node[now].rchild);
    }
}
int main()
{
    scanf("%d",&n);
    int lchild,rchild;
    for(int i=0;i<n;i++){
        scanf("%d%d",&lchild,&rchild);
        Node[i].lchild=lchild;
        Node[i].rchild=rchild;
    }
    for(int i=0;i<n;i++){
        scanf("%d",&in[i]);
    }
    sort(in,in+n);
    inorder(0);
    Layerorder(0);
    return 0;
}

只把中序遍历模板稍微改一下就可以了

A1127 构树 调换位置输出

#include<stdio.h>
#include<algorithm>
#include<queue>
#include<stdlib.h>
#include<vector>
using namespace std;
const int maxn=50;
struct node{
    int data,layer0;
    node* lchild;
    node* rchild;
};
int n,in[maxn],post[maxn];
int maxlayer=0;
int layer[maxn]={0};
vector<int>v;
node* Create(int inl,int inr,int postl,int postr){
    if(postl>postr)return NULL;
    node* root=new node;
    root->data=post[postr];
    root->lchild=root->rchild=NULL;
    int k=0;
    while(in[k]!=post[postr])k++;
    int numleft=k-inl;
    root->lchild=Create(inl,k-1,postl,postl+numleft-1);
    root->rchild=Create(k+1,inr,postl+numleft,postr-1);
    return root;
}
void layerorder(node* root){
    queue<node*>q;
    root->layer0=1;
    q.push(root);
    while(!q.empty()){
        node* now=q.front();
        q.pop();
        v.push_back(now->data);
        layer[now->layer0]++;
        maxlayer=max(maxlayer,now->layer0);
        if(now->lchild!=NULL){
            now->lchild->layer0=now->layer0+1;
            q.push(now->lchild);
        }
        if(now->rchild!=NULL){
            now->rchild->layer0=now->layer0+1;
            q.push(now->rchild);
        }
    }
}
int main()
{
// 	freopen("input.txt","r",stdin);
    scanf("%d",&n);
    for(int i=0;i<n;i++)scanf("%d",&in[i]);
    for(int i=0;i<n;i++)scanf("%d",&post[i]);
    node* root=Create(0,n-1,0,n-1);
    layerorder(root);
    int sum=0;
    for(int i=1;i<=maxlayer;i=i+2){
    	reverse(v.begin()+sum,v.begin()+sum+layer[i]);
    	sum+=layer[i]+layer[i+1];
	}  //调换位置
    for(int i=0;i<v.size();i++){
        printf("%d",v[i]);
        if(i!=v.size()-1)printf(" ");
    }
    return 0;
}

按层序遍历的顺序把数存到数组中,并记录每层节点的个数和最大深度,最后把数组的数用reverse调换位置,输出

A1115 数后两层节点

#include <iostream>
#include <vector>
using namespace std;
struct node {
    int v;
    struct node *left, *right;
};
node* build(node *root, int v) {
    if(root == NULL) {
        root = new node();
        root->v = v;
        root->left = root->right = NULL;
    } else if(v <= root->v)
        root->left = build(root->left, v);
    else
        root->right = build(root->right, v);
    return root;
}
vector<int> num(1000);
int maxdepth = -1;
void dfs(node *root, int depth) {
    if(root == NULL) {
        maxdepth = max(depth, maxdepth);
        return ;
    }
    num[depth]++;
    dfs(root->left, depth + 1);
    dfs(root->right, depth + 1);
    
}
int main() {
    int n, t;
    scanf("%d", &n);
    node *root = NULL;
    for(int i = 0; i < n; i++) {
        scanf("%d", &t);
        root = build(root, t);
    }
    dfs(root, 0);
    printf("%d + %d = %d", num[maxdepth-1], num[maxdepth-2], num[maxdepth-1] + num[maxdepth-2]);
    return 0;
}

A1138

A1110 判断完全二叉树 中等题

#include<stdio.h>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
    int lchild,rchild;
}Node[50];
int isroot[50]={0};
int n;
int maxid=-1,finmax;
string a,b;int child1,child2;
int getid(string a){
    if(a=="-")return -1;
    else return stoi(a);
}
void DFS(int root,int index){
//     if(index>maxid){
//         maxid=index;
//         finmax=root;
//     }
//     if(Node[root].lchild!=-1)DFS(Node[root].lchild,index*2);
//     if(Node[root].rchild!=-1)DFS(Node[root].rchild,index*2+1);
    if(root==-1)return;
    if(index>maxid){
        maxid=index;
        finmax=root;
    }
    DFS(Node[root].lchild,index*2);
    DFS(Node[root].rchild,index*2+1);
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a>>b;
        child1=getid(a);
        child2=getid(b);
        isroot[child1]++;
        isroot[child2]++;
        Node[i].lchild=child1;
        Node[i].rchild=child2;
    }
    int root=-1;
    for(int i=0;i<n;i++){
        if(isroot[i]==0){
            root=i;
            break;
        }
    }
    DFS(root,1);
    if(maxid==n)printf("YES %d\n",finmax);
    else printf("NO %d\n",root);
    return 0;
}

DFS函数里加入编号

A1143

A1151

A1107 课程团体 并查集

```c++
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=1010;
int n,k,h;
int father[maxn],isroot[maxn]={0},course[maxn]={0};
int findfather(int a){
    if(father[a]==a)return a;
    else{
        int F=findfather(father[a]);
        father[a]=F;
        return F;
    }
}
void Union(int a,int b){
    int A=findfather(a);
    int B=findfather(b);
    if(A!=B){
        father[B]=father[A];
    }
}
bool cmp(int a,int b){
    return a>b;
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<=n;i++){
        father[i]=i;
    }
    for(int i=1;i<=n;i++){
        scanf("%d:",&k);
        for(int j=0;j<k;j++){
            scanf("%d",&h);
            if(course[h]==0)course[h]=i;
            Union(course[h],i);
        }
    }
    for(int i=1;i<=n;i++){
        isroot[findfather(i)]++;
    }
    sort(isroot+1,isroot+n+1,cmp);
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(isroot[i]!=0)cnt++;
    }
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;i++){
        printf("%d",isroot[i]);
        if(i!=cnt)printf(" ");
        else printf("\n");
    }
    return 0;
}
```

难点:要把课程和第一个人对应起来作为根节点建立并查集,数团体的方法要记住,遍历每一个人找父亲节点并加1,,一举两得。

易错点:由于开始时course数组初始化为0,所以在主函数输入时人名不能从0开始。也可使用map代替course数组

A1118 鸟 基础并查集

```c++
#include<stdio.h>
int n,k,h;
const int maxn=10010;
int father[maxn],isroot[maxn]={0},max=0;
int findfather(int v){
    if(v==father[v])return v;
    else{
        int F=findfather(father[v]);
        father[v]=F;
        return F;
    }
}
void Union(int a,int b){
    int fA=findfather(a);
    int fB=findfather(b);
    if(fA!=fB){
        father[fA]=fB;
    }
    return;
}
int main()
{
    for(int i=0;i<maxn;i++){
        father[i]=i;
    }
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&k);
        int temp;
        scanf("%d",&temp);
        if(temp>max)max=temp;
        for(int j=1;j<k;j++){
            scanf("%d",&h);
            if(h>max)max=h;
            Union(temp,h);
        }
    }
    for(int i=1;i<=max;i++){
        isroot[findfather(i)]++;
    }
    int cnt=0;
    for(int i=0;i<maxn;i++){
        if(isroot[i]!=0)cnt++;
    }
    printf("%d %d\n",cnt,max);
    int n2,a,b;
    scanf("%d",&n2);
    for(int i=0;i<n2;i++){
        scanf("%d %d",&a,&b);
        if(findfather(a)==findfather(b))printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
```

注意审题系列

>  It is guaranteed that the birds in all the pictures are numbered continuously from 1 to some number that is no more than 10^4

A1034 犯罪团伙 难

暂时是用图做的,还不会并查集的做法,感觉并查集应该更麻烦,以后会了再更新

```c++
#include<stdio.h>
#include<iostream>
#include<string>
#include<map>
#include<algorithm> 
using namespace std;
const int maxn=2020;
int m,s;
string a,b;int child1,child2,c;
int G[maxn][maxn]={0};
int weight[maxn]={0};
int vis[maxn]={0};
map<string,int>strtoint;
map<int,string>inttostr;
map<string,int>Gangtoint;
int finid=-1,maxweight=-1,finsum=0,finsumper=0;
int index=1;
int getid(string a){
    if(strtoint[a]==0){
        strtoint[a]=index;
        inttostr[index]=a;
        return index++;
    }else{
        return strtoint[a];
    }
}
void DFS(int u){
    if(weight[u]>maxweight){
        maxweight=weight[u];
        finid=u;
    }
    vis[u]=1;
    finsumper++;
    for(int v=1;v<index;v++){
        if(G[u][v]!=0){
            finsum+=G[u][v];
            G[u][v]=G[v][u]=0;
            if(vis[v]==0){
                DFS(v);
            }
        }
    }
}
void DFSTrave(){
    for(int i=1;i<index;i++){
        if(vis[i]==0){
            finid=-1,maxweight=-1,finsum=0,finsumper=0;
            DFS(i);
            if(finsumper>2&&finsum>s){
                Gangtoint[inttostr[finid]]=finsumper;
            }
        }
    }
}
int main()
{
    cin>>m>>s;
    for(int i=0;i<m;i++){
        cin>>a>>b>>c;
        child1=getid(a);
        child2=getid(b);
        G[child1][child2]+=c;
        G[child2][child1]+=c;
        weight[child1]+=c;
        weight[child2]+=c;
    }
    DFSTrave();
    cout<<Gangtoint.size()<<endl;
    for(auto it=Gangtoint.begin();it!=Gangtoint.end();it++){
        cout<<it->first<<" "<<it->second<<endl;
    }
    return 0;
}



```

```

简单最短路径题 第二标准是花费,跟路径一样,注意初始化的时候也与路径一样为INF,在定义变量前想好变量名,别重复

在走完一条路径后要把路径删掉,还原到初始化状态,(要删两条边,跟输入时一样)

巨大坑点测试点2:题中两个人之间可能不止打一次电话,所以输入构建图的时候必须是加,图的初始化必须是0

A1114 家庭房产 难 已做

明天11月13日必更新此题的并查集解法

好难,写了快俩小时了还是不会,感觉自己太浮躁,写的代码逻辑混乱,各种变量写着写着就晕了,看来得规范一下格式,先把做题步骤清晰写出来,在开始敲代码。明天在更新这题吧,还是看动漫要紧。。

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
const int maxn=10001;
int n,m;
int father[maxn],vis[maxn]={0};
struct node1{
    int id,fa,ma,child[10];
    double cnt1,area1;
}per[1001];
struct node2{
    int minid,numpeople,flag;
    double cnt2,area2;
}family[maxn];
int findfather(int v){
    if(father[v]==v)return v;
    else{
        int F=findfather(father[v]);
        father[v]=F;
        return F;
    }
}
void Union(int a,int b){
    int FA=findfather(a);
    int FB=findfather(b);
    if(FA<FB)father[FB]=FA;
    else if(FA>FB)father[FA]=FB;
}
bool cmp(node2 a,node2 b){
    if(a.flag!=b.flag)return a.flag>b.flag;
    else if(a.area2!=b.area2)return a.area2>b.area2;
    else return a.minid<b.minid;
}
int main()
{
//  	freopen("input.txt","r",stdin);
   	for(int i=0;i<maxn;i++){
        family[i].numpeople=family[i].flag=0;
        family[i].cnt2=family[i].area2=0.0;
        father[i]=i;
    }
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d %d %d %d",&per[i].id,&per[i].fa,&per[i].ma,&m);
        vis[per[i].id]=1;
        if(per[i].fa!=-1){                            //写错数,写成1了
            Union(per[i].id,per[i].fa);
            vis[per[i].fa]=1;
        }
        if(per[i].ma!=-1){
            Union(per[i].id,per[i].ma);
            vis[per[i].ma]=1;
        }
        for(int j=0;j<m;j++){
            scanf("%d",&per[i].child[j]);
            Union(per[i].id,per[i].child[j]);
            vis[per[i].child[j]]=1;
        }
        scanf("%lf %lf",&per[i].cnt1,&per[i].area1);
    }
    for(int i=0;i<n;i++){
        int f=findfather(per[i].id);
        family[f].minid=f;
        family[f].cnt2+=per[i].cnt1;
        family[f].area2+=per[i].area1;
        family[f].flag=1;
    }
    int cnt=0;
    for(int i=0;i<maxn;i++){
        if(vis[i]==1){
            int f=findfather(i);
            family[f].numpeople++;
        }
        if(family[i].flag)cnt++;
    }
    for(int i=0;i<maxn;i++){
        if(family[i].flag==1){
            family[i].cnt2=family[i].cnt2*(1.0)/(family[i].numpeople*1.0);
            family[i].area2=family[i].area2*1.0/(family[i].numpeople*1.0);
        }
    }
    sort(family,family+maxn,cmp);
    printf("%d\n",cnt);
    for(int i=0;i<cnt;i++){
        printf("%04d %d %.3lf %.3lf\n",family[i].minid,family[i].numpeople,family[i].cnt2,family[i].area2);
    }
    return 0;
}
//8888的祖先莫名变成0 

看的柳神的代码,仿照着写出来的。

两个结构体,一个用来读输入,一个用来存储家庭,vis数组用来标记是否是人,在并查集合并操作中直接让最小值作为根节点,非常巧妙的做法。家庭成员个数,和家庭数最后单独处理



求路径问题

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值