【拓扑排序】【NOIP普及2013T4】车站分级 Level

该博客介绍了一道关于铁路线上的火车站分级问题,要求根据车次停靠规则推算最少的级别数。通过分析,作者提出建立有向图并进行拓扑排序的方法,以找出最低级别并逐渐删除边。文章还提到了使用DFS和邻接矩阵等不同尝试,最终建议使用链表实现。
摘要由CSDN通过智能技术生成

题目描述

  一条单向的铁路线上,依次有编号为 1, 2, …, n 的 n 个火车站。每个火车站都有一个级别,最低为 1 级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 x,则始发站、终点站之间所有级别大于等于火车站 x 的都必须停靠。(注意:起始站和终点站自然也算作事先已知需要停靠的站点)
  例如,下表是 5 趟车次的运行情况。其中,前 4 趟车次均满足要求,而第 5 趟车次由于停靠了 3 号火车站(2 级)却未停靠途经的 6号火车站(亦为 2 级)而不满足要求。
Table
  现有 m 趟车次的运行情况(全部满足要求),试推算这n个火车站至少分为几个不同的级别。

输入

第一行包含 2 个正整数 n , m,用一个空格隔开。
i+1 (1im) 中,首先是一个正整数 si(2sin) ,表示第 i 趟车次有 si 个停靠站;接下来有 si 个正整数,表示所有停靠站的编号,从小到大排列。每两个数之间用一个空格隔开。输入保证所有的车次都满足要求。

输出

输出只有一行,包含一个正整数,即 n 个火车站最少划分的级别数。

数据范围

对于 20%的数据,1n,m10
对于 50%的数据, 1n,m100
对于 100%的数据, 1n,m1000

样例输入1

9 2
4 1 3 5 6
3 3 5 6

样例输出1

2

样例输入2

9 3
4 1 3 5 6
3 3 5 6
3 1 5 9

样例输出2

3


一开始毫无头绪是不是哈哈哈哈哈哈
我也是

直接说吧,这道题你需要建图并跑拓扑排序
什么?整个就一条铁轨你让我建个图?按火车建啊还是按车站建啊还是???
嗯我们来分析一下。
每组数据给的都是起点和终点之间级别大于等于某个车站的所有车站,然而这并没有什么卵用,看不出来谁和谁是一级中间又隔了几级然后还有几级在这趟车的外面,外面还有多少级。
因为重要的事他没说:
起点终点之间所有没有显示出来的都是比所有的给出的车站级别低的。
所以?
建立有向图,从一条火车线中未给出的指向给出的,表示级别低。
然后?
然后就找入度为0的是最低级然后往下删边删到底就行。
好吧太罗嗦了,上代码:
【并不漂亮】

#include <cstdio>
#include <cstring>
int n, m, len[1000]={0}, maxdep=0, temp[1000];
//len:入度 maxdep:最优解 temp:临时存个数
bool used[1000], graph[1000][1000]={0};
//used:记录是否为车线中给出的站 graph:从后面指向前面
int main()
{
    scanf("%d%d", &n, &m);
    int c;
    for(int i=0;i<m;i++){
        scanf("%d", &c);
        memset(used, 0, sizeof(bool)*n);
        for(int i=0;i<c;i++){
            scanf("%d", &temp[i]);
            temp[i]-=1;                             //0base 你们随意【
            used[temp[i]]=1;
        }
        for(int k=temp[0];k<temp[c-1];k++)
            if(!used[k])                            //智力-2
                for(int j=0;j<c;j++)                //教训:尽量减少【判断】次数
                   if(!graph[k][temp[j]]){          //毕竟比较也是一次运算
                        graph[k][temp[j]]=1;        //一开始颠倒了j k
                        len[temp[j]]++;             //于是超时
                    }                               //智力+2
    }
    bool f=1;
    int *cpy=new int[n];                            //临时保存一下 防止后面出0影响结果
    memcpy(cpy, len, sizeof(int)*n);
    while(f){
        f=0;
        maxdep++;                                   //删掉一层加一次
        for(int i=0;i<n;i++){
            if(len[i]>0)                            //找入度为0
                continue;
            f=1;
            for(int j=0;j<n;j++)
                cpy[j]-=graph[i][j];                //删边
            cpy[i]=666;                             //666
        }
        memcpy(len, cpy, sizeof(int)*n);            //搞回去
    }
    printf("%d\n", maxdep-1);                       //最后会多加一次
    return 0;
}

这种伪·拓扑排序应该都能写吧因为没有排序【
加上排序应该能优化一部分
据说这道题dfs也可以过
我一开始写的dfs应该是记忆化还是炸了所以超时
然后改成了删边做法还是超时一个点
然后我以为邻接表难道很慢
于是改成了喜闻乐见的邻接矩阵还是超时
后来是上面那个呵呵的优化

手写链表大法好,
除非脑残挂不了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值