2022.1.18

上午看了二叉树的一些题,发现不会写题。又继续看大话数据结构

下午学长讲二叉树的前,中,后序遍历,建立。还有知道前中序,推出后序等。然后这个貌似还是不会写。

晚上在洛谷写了一道新二叉树,两道并查集题。

题目描述

输入一串二叉树,输出其前序遍历。

输入格式

第一行为二叉树的节点数 nn。(1 \leq n \leq 261≤n≤26)

后面 nn 行,每一个字母为节点,后两个字母分别为其左右儿子。

空节点用 * 表示

输出格式

二叉树的前序遍历。

输入输出样例

输入 #1复制

6
abc
bdi
cj*
d**
i**
j**

输出 #1复制

abdicj

思路:只有26个字母,可以用数组来表示所在的结点,用两个数组各来表示它是否出现过和它是不是根结点(它是不是某个节点的左右儿子),最后找到根结点,然后前序遍历

#include<stdio.h>

int n;
int b[26]={0},c[26]={0};

struct node
{
    char l,r;
}tree[26];

void creat(char root,char left,char right)
{
    c[root-'a']=1;//标记它出现过了
    if(left!='*'){
        tree[root-'a'].l=left;
        b[left-'a']=1;//标记它不是根节点
        c[left-'a']=1;//标记它出现过了
    }
    else tree[root-'a'].l='*';

    if(right!='*'){
        tree[root-'a'].r=right;
        b[right-'a']=1;
        c[left='a']=1;
    }
    else tree[root-'a'].r='*';
}

void Pretree(char root)//前序遍历
{
    if(root!='*'){
        printf("%c",root);
        Pretree(tree[root-'a'].l);
        Pretree(tree[root-'a'].r);
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        char a[4];
        scanf("%s",a);
        creat(a[0],a[1],a[2]);
    }
    for(int i=0;i<27;i++){
        if(b[i]==0&&c[i]==1){//遍历找到根节点
            Pretree(i+'a');
            break;
        }
    }
    printf("\n");
}

题目背景

小明在 A 公司工作,小红在 B 公司工作。

题目描述

这两个公司的员工有一个特点:一个公司的员工都是同性。

A 公司有 NN 名员工,其中有 PP 对朋友关系。B 公司有 MM 名员工,其中有 QQ 对朋友关系。朋友的朋友一定还是朋友。

每对朋友关系用两个整数 (X_i,Y_i)(Xi​,Yi​) 组成,表示朋友的编号分别为 X_i,Y_iXi​,Yi​。男人的编号是正数,女人的编号是负数。小明的编号是 11,小红的编号是 -1−1。

大家都知道,小明和小红是朋友,那么,请你写一个程序求出两公司之间,通过小明和小红认识的人最多一共能配成多少对情侣(包括他们自己)。

输入格式

输入的第一行,包含 44 个空格隔开的正整数 N,M,P,QN,M,P,Q。

之后 PP 行,每行两个正整数 X_i,Y_iXi​,Yi​。

之后 QQ 行,每行两个负整数 X_i,Y_iXi​,Yi​。

输出格式

输出一行一个正整数,表示通过小明和小红认识的人最多一共能配成多少对情侣(包括他们自己)。

输入输出样例

输入 #1复制

4 3 4 2
1 1
1 2
2 3
1 3
-1 -2
-3 -3

输出 #1复制

2

说明/提示

对于 30 \%30% 的数据,N,M \le 100N,M≤100,P,Q \le 200P,Q≤200;

对于 80 \%80% 的数据,N,M \le 4 \times 10^3N,M≤4×103,P,Q \le 10^4P,Q≤104;

对于 100 \%100% 的数据,N,M \le 10^4N,M≤104,P,Q \le 2 \times 10^4P,Q≤2×104。

 先找出小红有多少个朋友,再找出小明有多少朋友,朋友少的那个就是最多情侣对。

#include<stdio.h>
#include<math.h>
int N,M,P,Q;
int f[10000];
int getf(int v)
{
    if(f[v]==v) return v;
    else{
        f[v]=getf(f[v]);//路径压缩
        return f[v];
    }
}

void merge(int x,int y)
{
    int t1,t2;
    t1=getf(x);
    t2=getf(y);
    if(t1!=t2){
        f[t2]=t1;
    }
    return;
}

int main()
{
    int s1=0,s2=0;
    scanf("%d%d%d%d",&N,&M,&P,&Q);
    for(int i=1;i<=N;i++)
        f[i]=i;
    for(int i=0;i<P;i++){
            int x,y;
        scanf("%d%d",&x,&y);
        merge(x,y);
    }
    int t=getf(1);
    for(int i=1;i<=N;i++)
        if(getf(f[i])==t) s1++;

    for(int i=1;i<=M;i++)
        f[i]=i;
    for(int i=0;i<Q;i++){
            int x,y;
        scanf("%d%d",&x,&y);
        merge(abs(x),abs(y));
    }
    t=getf(1);
    for(int i=1;i<=M;i++)
        if(getf(f[i])==t) s2++;
    if(s1>s2) printf("%d\n",s2);
    else printf("%d",s1);
    //printf("%d %d\n",s1,s2);
}

题目背景

AA地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车。政府派人修复这些公路。

题目描述

给出A地区的村庄数NN,和公路数MM,公路是双向的。并告诉你每条公路的连着哪两个村庄,并告诉你什么时候能修完这条公路。问最早什么时候任意两个村庄能够通车,即最早什么时候任意两条村庄都存在至少一条修复完成的道路(可以由多条公路连成一条道路)

输入格式

第11行两个正整数N,MN,M

下面MM行,每行33个正整数x, y, tx,y,t,告诉你这条公路连着x,yx,y两个村庄,在时间t时能修复完成这条公路。

输出格式

如果全部公路修复完毕仍然存在两个村庄无法通车,则输出-1−1,否则输出最早什么时候任意两个村庄能够通车。

输入输出样例

输入 #1复制

4 4
1 2 6
1 3 4
1 4 5
4 2 3

输出 #1复制

5

说明/提示

N \le 1000,M \le 100000N≤1000,M≤100000

x \le N,y \le N,t \le 100000x≤N,y≤N,t≤100000

思路:先将时间从小到大排序,然后开始合并,遇到两个村不通的就合并然后路的条数+1,如果两个村可以通就不管它,当路等于N-1就说明都通了,否则就没通。

#include<stdio.h>

struct node
{
    int x,y,t;
}a[100001],w;

int N,M;
int f[100001];

void qs(int l,int r)//快排
{
    int mid=a[(l+r)/2].t;
   // printf("%d\n",mid);
    int i=l,j=r;
    while(i<=j){
        while(a[i].t<mid) i++;
        while(a[j].t>mid) j--;
        if(i<=j){
            w=a[i];
            a[i]=a[j];
            a[j]=w;
            i++;
            j--;
        }
    }
    if(i<r) qs(i,r);
    if(j>l) qs(l,j);
}

int getf(int v)
{
    if(f[v]==v) return v;
    else{
        f[v]=getf(f[v]);//路径压缩
        return f[v];
    }
}

int merge(int x,int y)
{
    int t1,t2;
    t1=getf(x);
    t2=getf(y);
    if(t1!=t2){//这两个村庄的'祖先'不同
        f[t2]=t1;
        return 1;
    }
    else return 0;
}

int main()
{
    int s=0,flag=0,T;
    scanf("%d%d",&N,&M);
    for(int i=1;i<=N;i++)
        f[i]=i;
    for(int i=1;i<=M;i++)
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].t);
    qs(1,M);
  //  for(int i=1;i<=M;i++)
    //    printf("%d %d %d\n",a[i].x,a[i].y,a[i].t);
    for(int i=1;i<=M;i++){
        if(merge(a[i].x,a[i].y)==1){
            s++;
            T=a[i].t;
        }
        if(s==N-1) {flag=1;break;}//只需N-1条路就行了
    }
    if(flag==1) printf("%d\n",T);
    else printf("-1\n");
}

 明天二叉树推导遍历结果。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值