蓝桥杯刷题冲刺 | 倒计时23天

作者:指针不指南吗
专栏:蓝桥杯倒计时冲刺

马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦

文章目录

  • 1.有向图的拓扑序列
  • 2.纸张尺寸
  • 3.数位排序

1.有向图的拓扑序列

  • 题目

    链接: 848. 有向图的拓扑序列 - AcWing题库

    给定一个 n 个点 m 条边的有向图,点的编号是 1 到 n,图中可能存在重边和自环。

    请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 −1。

    若一个由图中所有点构成的序列 A 满足:对于图中的每条边 (x,y) , x 在 A 中都出现在 y 之前,则称 A 是该图的一个拓扑序列。

    输入格式

    第一行包含两个整数 n 和 m。

    接下来 m 行,每行包含两个整数 x 和 y,表示存在一条从点 x 到点 y 的有向边 。

    输出格式

    共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。

    否则输出 −1。

    数据范围

    1≤n,m≤ 1 0 5 10^5 105

    输入样例:

    3 3
    1 2
    2 3
    1 3
    

    输出样例:

    1 2 3
    
  • 题里面的对拓扑图的定义,虽然很简洁,但我通过网上搜索资料,找到更加易懂的定义

    • 一个有向图,如果图中有入度为 0 的点,就把这个点删掉,同时也删掉这个点所连的边。

    • 一直进行上面出处理,如果所有点都能被删掉,则这个图可以进行拓扑排序。


    如下图图转自acwing


    蓝桥杯刷题冲刺 | 倒计时23天_第1张图片

    开始时,图是这样的状态,发现A的入度为 0,所以删除A和A上所连的边,结果如下图:

    蓝桥杯刷题冲刺 | 倒计时23天_第2张图片

    这时发现B的入度为 0,C的入度为 0,所以删除B和B上所连的边、C和C上所连的边,结果如下图:

    蓝桥杯刷题冲刺 | 倒计时23天_第3张图片

    这时发现发现D的入度为 0,所以删除D和D上所连的边(如果有就删),结果如下图:
    蓝桥杯刷题冲刺 | 倒计时23天_第4张图片

    这时整个图被删除干净,所有能进行拓扑排序。

  • 思路

    queue<int> q;
    q.push(入度=0)//把所有入度=0的点,放进队列里面
    while(q.empty())
    {
    	t=对头
        枚举所有t的出边 t->j
      	删掉 t->j 这个边,d[j]--  //入度--
        if(d[j]==0)
            q.push(j); //入队
    }
    
  • 题解

    #include
    using namespace std;
    
    const int N=1e5+10;
    
    int h[N],e[N*2],ne[N*2],idx;
    int d[N];  //d表示入度
    int q[N],tt=-1,hh=0;
    
    int n,m;
    
    void add(int a,int b)  //定义一个边
    {
        e[idx]=b,ne[idx]=h[a],h[a]=idx++;
    }
    
    void topsort()  //拓扑排序函数
    {
        for(int i=1;i<=n;i++)  //遍历所有顶点,将入度=0的顶点,放进队列里面
            if(d[i]==0) q[++tt]=i;  //使用 ++tt的好处是,最后tt就是我们想要的数,没有多加1;
        
        while(hh<=tt)  //队列不空
        {
            int a=q[hh++];  //取出 队头
            for(int i=h[a];i!=-1;i=ne[i])  //删除以a为起点的边
            {
                int b=e[i];  //有一边是 a 指向 b;
                d[b]--; //删除a->b 的边,b的入度--
                if(d[b]==0)  //入度=0,入队
                    q[++tt]=b; 
            }
        }
        
        if(tt==n-1) //如果所有顶点都进入过 队列,则说明 这个图 有拓扑序列
        {
            for(int i=0;i<n;i++)  //我们顶点入队的顺序就是拓扑序列,直接输出就可以
                printf("%d ",q[i]);
        }
        else
            printf("-1");  //否则,该图没有拓扑序列,输出 -1
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        
        memset(h,-1,sizeof h);  
        
        while(m--)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b);  //模板 默写一遍
            d[b]++;  //被指向的顶点的入度++
        }
        
        topsort();  //进行拓扑排序
        
        return 0;
    }
    
  • 补充

    • 有向无环图才会有拓扑序列,所以有向无环图又称为拓扑图,无向图没有,环也没有
    • 入度:有几条边进入某个顶点;出度:有几条边从某个顶点出去

2.纸张尺寸

  • 题目

    链接: 纸张尺寸 - 蓝桥云课 (lanqiao.cn)

    在 ISO 国际标准中定义了 A0 纸张的大小为 1189mm ×× 841mm, 将 A0 纸 沿长边对折后为 A1 纸, 大小为 841mm ×× 594mm, 在对折的过程中长度直接取 下整 (实际裁剪时可能有损耗)。将 A1 纸沿长边对折后为 A2 纸, 依此类推。

    输入纸张的名称, 请输出纸张的大小。

    输入格式

    输入一行包含一个字符串表示纸张的名称, 该名称一定是 A0、A1、A2、 A3、A4、A5、A6、A7、A8、A9 之一。

    输出格式

    输出两行,每行包含一个整数,依次表示长边和短边的长度。

    样例输入1

    A0
    

    样例输出1

    1189
    841
    

    样例输入 2

    A1
    

    样例输出 2

    841
    594
    
  • 我的题解

    #include
    using namespace std;
    
    int l[10],w[10];  //用两个数组分别表示10种纸张的长、宽
    
    int main()
    {
        int a=1189,b=841;  //初始化
        
        l[0]=a,w[0]=b;
        for(int i=1;i<10;i++)
        {
            l[i]=w[i-1];  //规律
            w[i]=l[i-1]/2;
        }
        
        char c;
        int x;
        scanf("%c%d",&c,&x);  //用 c 吃掉 A,没啥用
        
        printf("%d\n%d",l[x],w[x]);  //输出
        
        return 0;
    }
    
  • 反思

    没有认真审题,以为每一次都是对半剪,还好调式了一遍

    注意最后的输出格式,别最后好不容易算对了,结果格式错了,太冤了

    2022年 C 组的题,还是很简单的

3.数位排序

  • 题目

    链接: 数位排序 - 蓝桥云课 (lanqiao.cn)

    小蓝对一个数的数位之和很感兴趣, 今天他要按照数位之和给数排序。当 两个数各个数位之和不同时, 将数位和较小的排在前面, 当数位之和相等时, 将数值小的排在前面。

    例如, 2022 排在 409 前面, 因为 2022 的数位之和是 6, 小于 409 的数位 之和 13 。

    又如, 6 排在 2022 前面, 因为它们的数位之和相同, 而 6 小于 2022 。

    给定正整数 n*,m, 请问对 1 到 n 采用这种方法排序时, 排在第 m 个的元 素是多少?

    输入格式

    输入第一行包含一个正整数 n

    第二行包含一个正整数 m

    输出格式

    输出一行包含一个整数, 表示答案。

    样例输入

    13
    5
    

    样例输出

    3
    

    样例说明

    1 到 13 的排序为: 1,10,2,11,3,12,4,13,5,6,7,8,9。第 5 个数为 3 。

    评测用例规模与约定

    对于 30% 的评测用例, 1≤mn≤300 。

    对于 50% 的评测用例, 1≤mn≤1000 。

    对于所有评测用例, 1≤mn 1 0 6 10^6 106

  • 我的题解

    #include
    using namespace std;
    
    const int N=1e6+10;
    
    struct node  //定义一个结构体,来放 每个数的原数和 各位和
    {
        int x;  //原数
        int y;  //各位数和
    }num[N]; 
    
    int sum(int x)  //求x各位数 的和
    {
        int sum=0;
        while(x>0)
        {
            sum+=x%10;
            x/=10;
        }
        return sum;
    }
    
    bool cmp(node a,node b) //结构体,重载
    {
        if(a.y!=b.y)  return a.y<b.y;  //从小到大
        return a.x<b.x;
    }
    
    int main()
    {
        int n,m;
        cin>>n>>m;
        
        for(int i=1;i<=n;i++)  //初始化
        {
            num[i].x=i;
            num[i].y=sum(i);
        }
        
        sort(num+1,num+1+n,cmp); //进行排序  sort函数的重载
        
        cout<<num[m].x;  //输出结果
        
        return 0;
    }
    
  • 反思

    第一次做的时候,想到了 set 和 map ,但是有忘记怎么写了,就直接看了题解

    • 原来还可以使用结构体,确实简单了不少

    • sort函数的重载,这个还挺重要的,之前没有认真学习过,学完图论后,再系统地学习一个符号的重载

Alt

你可能感兴趣的:(蓝桥杯倒计时冲刺,蓝桥杯,算法,职场和发展)