zoukankan      html  css  js  c++  java
  • 洛谷P1983 车站分级

    P1983 车站分级

      • 297通过
      • 1.1K提交
    • 题目提供者该用户不存在
    • 标签图论贪心NOIp普及组2013
    • 难度普及/提高-

    提交该题 讨论 题解 记录

    最新讨论

    • 求帮忙指出问题!
    • 我这么和(diao)谐(zha)…

    题目描述

    一条单向的铁路线上,依次有编号为 1, 2, …, n 的 n 个火车站。每个火车站都有一个级

    别,最低为 1 级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车

    次停靠了火车站 x,则始发站、终点站之间所有级别大于等于火车站 x 的都必须停靠。(注

    意:起始站和终点站自然也算作事先已知需要停靠的站点)

    例如,下表是 5 趟车次的运行情况。其中,前 4 趟车次均满足要求,而第 5 趟车次由于

    停靠了 3 号火车站(2 级)却未停靠途经的 6 号火车站(亦为 2 级)而不满足要求。

    现有 m 趟车次的运行情况(全部满足要求),试推算这 n 个火车站至少分为几个不同的

    级别。

    输入输出格式

    输入格式:

    输入文件为 level.in。

    第一行包含 2 个正整数 n, m,用一个空格隔开。

    第 i + 1 行(1 ≤ i ≤ m)中,首先是一个正整数 si(2 ≤ si

    ≤ n),表示第 i 趟车次有 si 个停

    靠站;接下来有 si个正整数,表示所有停靠站的编号,从小到大排列。每两个数之间用一个

    空格隔开。输入保证所有的车次都满足要求。

    输出格式:

    输出文件为 level.out。

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

    输入输出样例

    输入样例#1:
    Case 1:
    9 2 
    4 1 3 5 6 
    3 3 5 6 
    
    Case 2:
    9 3 
    4 1 3 5 6 
    3 3 5 6 
    3 1 5 9 
    
    输出样例#1:
    Case 1:
    2
    
    Case 2:
    3
    

    说明

    对于 20%的数据,1 ≤ n, m ≤ 10;

    对于 50%的数据,1 ≤ n, m ≤ 100;

    对于 100%的数据,1 ≤ n, m ≤ 1000。

    分析:看到这道题的时候一点思路都没有......再读一次题发现也没有思路......再读一次终于明白了题目的意思.在火车从起点到终点的所有站点中,停靠的站点的车站级别一定比不停靠的高,设起点为s,终点为t,如果只有一趟火车,那么所有停靠的站的等级只需要比不停靠的站的最高值多1即可.如果再增加一趟火车,这趟火车在上一趟火车的起始点之内,那么还要再+1,如果在起始点之外那么就和一趟火车一样处理,如果有n趟呢......可以想到如果拓扑排序.在起始点内不能停靠的站向可以停靠的站连有向边,然后找到入度为0的点(没有边指向的点),删除这个点和这个点所连出去的所有路径,路径指向的点的入度-1,当所有入度为0的点(撤销原入度为0后入度变为0在第一轮不解决)都解决了之后,进行下一轮,进行一轮就累加一下计数器,最后输出结果即可.这是拓扑排序的基本方法,很好理解,实在不能理解画个图就能理解了.还有一个问题,为什么要多个点在同一轮进行处理呢?可以想到如果按照之前提到的方式建图,那么就会有多个拓扑序列,我们可以认为每一次对所有的拓扑序列的操作是等价的,直到没有入度为0的点即可.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 1010;
    int n, m, flag[maxn], first, ans, vis[maxn], s, a[maxn], e[maxn][maxn], rudu[maxn], stack1[maxn], top;
    
    void init()
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++)
        {
            memset(flag, 0, sizeof(flag));
            scanf("%d", &s);
            for (int j = 1; j <= s; j++)
            {
                scanf("%d", &a[j]);
                flag[a[j]] = 1;
            }
            for (int j = a[1]; j <= a[s]; j++)
                if (!flag[j])
                    for (int k = 1; k <= s; k++)
                        if (!e[j][a[k]])
                        {
                            e[j][a[k]] = 1;
                            rudu[a[k]]++;
                        }
        }
    }
    
    void tp()
    {
        first = 1;
        while (top != 0 || first)
        {
            first = 0;
            top = 0;
            for (int i = 1; i <= n; i++)
                if (!rudu[i] && !vis[i])
                {
                    stack1[++top] = i;
                    vis[i] = 1;
                }
            for (int i = 1; i <= top; i++)
                for (int j = 1; j <= n; j++)
                    if (e[stack1[i]][j])
                    {
                        e[stack1[i]][j] = 0;
                        rudu[j]--;
                    }
            ans++;
        }
        ans--;  //因为当top为0的时候累加器还在累加,所以最后要减去1
    }
    
    int main()
    {
        init();
        tp();
        printf("%d", ans);
    
        return 0;
    }
  • 相关阅读:
    Linux下安装启动nginx的过程
    shell编程
    Linux中的权限管理
    Linux中的模式转换
    Linux入门2
    Linux入门1
    数据库的多表查询及左右连接
    Python命令行参数sys.argv[]
    Python 读取csv文件到excel
    高级技巧
  • 原文地址:https://www.cnblogs.com/zbtrs/p/5804618.html
Copyright © 2011-2022 走看看