2017.4.3 校内赛 图论(bricks)(drive)(graph)(airport)

这篇博客介绍了2017年一场校内赛的四道图论题目,包括Bricks(使用并查集解决)、Drive(最短路问题)、Graph(判断单向连通图,用Tarjan求SCC和拓扑排序)、Airplane(最小生成树在航空公司并购问题中的应用)。文章详细讲解了每道题目的解题思路和算法实现,如并查集维护有序集合、SPFA或堆优化Dijkstra求最短路、拓扑排序判断单向连通图以及最小生成树的应用策略。
摘要由CSDN通过智能技术生成

这次考试是远在北京的JYB出的,飞了起来。

Problem 1. bricks

Input file: bricks.in
Output file: bricks.out
Time limit: 1 second
jyb 在BUAA 天天被大神虐,所以只能去搬砖了。
终于在2019 年的夏天,菜菜的jyb 找不到工作,真的去工地搬砖了。jyb 的工头cky 是一个很麻烦的人,他会让jyb 按某种方式搬砖,还问会问一些奇怪的问题。
现在有n 块砖,m 次操作。操作有两种:
1. M x y 把编号为x 的砖所在的一摞砖搬到编号为y 的砖所在的一摞砖的上面。如果x 和y 在同一摞砖则忽略这个操作。(最初,每块砖都是单独一摞)
2. C x 询问x 下面压着多少块砖。
jyb 搬砖实在是太累了,想请你帮忙回答一下cky 工头的询问。

Bricks:并查集

用链表什么的暴力枚举题意,最坏复杂度是O(m^2)的。
注意到每次都是移动一摞砖,其实问题就是集合的合并,只是这个集合是一个有序的,我们还需要知道每个元素在集合中的位置。我们可以利用并查集高效的来解决。我们引入一个dep数组,对于祖先节点(将每摞砖最上方的一块设为祖先,设最下面的为祖先也是可以的),我们记录该集合中一共有多少块砖,对于其他节点,我们记录它上方有多少块砖,这样我们可以很容易地计算出下方有多少块。这样在合并x和y(设他们祖先为fx,fy)时,我们将dep[fx]赋给dep[fy](因为移到了上方,fx有多少块fy上方就有多少块),然后dep[fx]要加上原本的dep[fy]。难点就是在合并的过程中,dep数组怎么维护。其实很简单,只需要在路径压缩时顺带维护即可,如果一个节点x的祖先fx不是祖先(即已被合并过),那么dep[x]加上dep[fx]即可(等于头上又多了一摞砖,所以要加上)。
时间复杂度O(α(m))

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
const int N=200000;
int n,m;
int father[N],down[N]/*下面的包括自己*/,up[N]/*每列最上面*/;
int getfather(int x)
{
    int t;
    if(father[x]!=x) 
    {
        t=father[x];
        father[x]=getfather(father[x]);
        up[x]+=up[t];
    }
    return father[x];
}
void move(int x,int y)
{
    x=getfather(x),y=getfather(y);
    if(x!=y)
    {
        father[y]=x;
        up[y]=down[x];
        down[x]+=down[y];//个数相加 
    } 
}
int main()
{
    freopen("bricks.in","r",stdin);
    freopen("bricks.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    father[i]=i,down[i]=1,up[i]=0;
    while(m--)
    {
        char s[10];
        int x,y;
        scanf("%s",s);
        if(s[0]=='M')
        {
            scanf("%d%d",&x,&y);
            move(x,y);
        }
        else
        {
            scanf("%d",&x);
            printf("%d\n",down[getfather(x)]-up[x]-1);
        }
    }
    return 0;
}

Problem 2. drive

Input file: drive.in
Output file: drive.out
Time limit: 2 second
工头cky 最近开了一家贸易公司,开始经商。作为cky 的忠实小弟,jyb 当了cky 老总的司机。一天晚上,cky 突然找到了一个新的客户,所以第二天一早要急着从成都去上海谈生意(设全国一共有n 个城市, 成都编号为1,上海编号为n),城市之间有高速公路,每条高速公路都有一个最高限速和长度。cky 想:我应该在今晚就告诉客户我最快多久能到上海,不然客户就可先和别人谈生意了。所以他就让jyb 计算一下最快多久能到。
jyb 作为一名经验丰富的老司机,看了一眼天气预报,天气预报说:全国范围内有一条高速公路第二天可能下大雨(大雨天气的话,车速会下降75%),但坑爹的是居然不知道是哪一条,准确信息要第二天一早才知道。现在jyb 拥有全国高速公路图,为了回答一个尽量早但又不失信于客户的时间,jyb 想请你帮帮忙。
ps: 虽然cky 很急,但是他还是告诫jyb 不能超速行驶。
第二天知道哪会下雨后,jyb 自然会作出正确的抉择。
迟到肯定就是失信于客户啦!

Drive:最短路

如果没有大雾天气,很显然就是求一个最短路就行了。但是由于大雾天气的存在

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值