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

    洛谷(P1983)车站分级(拓扑排序)

    目录

    • 题目描述

    • 题目分析

    • 思路分析

    • 代码实现


    题目描述

    题目在洛谷(P1983)

    题目:

    一条单向的铁路线上,依次有编号为 (1, 2, …, n1,2,…,n)(n)个火车站。每个火车站都有一个级别,最低为 11 级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 (x),则始发站、终点站之间所有级别大于等于火车站(x) 的都必须停靠。(注意:起始站和终点站自然也算作事先已知需要停靠的站点)

    例如,下表是(5)趟车次的运行情况。其中,前(4)趟车次均满足要求,而第(5)趟车次由于停靠了(3)号火车站((2)级)却未停靠途经的(6)号火车站(亦为(2)级)而不满足要求。img

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

    输入输出格式:

    输入:第一行包含(2)个正整数(n, m),用一个空格隔开。

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

    输出:一个正整数,即(n)个火车站最少划分的级别数。


    题目分析

    ​ 刚刚看到这道题时,我并没有读懂题,觉得是要用一个(dp)或者搜索什么的(也有可能是我搜索题做多了

    看到题目,我们知道,假设一个车次从(x)车站驶向(y)车站,(c_i)表示第(i)个车站的车站等级。那么中间的(c_i(x leq i leq y))一定满足(c_ileq c_x)(c_i leq c_y)。这样的话,我们就可以构造出一个有向图,级别低的车站指向级别高的车站。这样一来,题目就转化成了拓扑排序的简单题了


    思路分析

    ​ 根据上面的题目分析,我们可以得出以下解题方法:

    首先将有向图建好,建图的方法是:对于每一个车次,其中停靠的车站我们不能确定与始发站和终点站的关系,那么我们就假设这些车站的等级是相同的,而中间没有停靠的车站则向停靠过的车站(包括始发站和终点站)连一条边。

    进行了这项操作之后,我们发现这(n)个车站各自有不同的入度,按照入度进行排序,如果有不同的入度,(ans++)最后的(ans)就是我们要求的答案。


    代码实现

    #include<bits/stdc++.h>
    using namespace std;
    
    const int MAXN=3000010;
    const int maxn=1005;
    
    int head[MAXN],to[MAXN],nxt[MAXN];
    int in[maxn],cnt,dep[maxn];
    int a[maxn],flag[maxn],vis[maxn][maxn],ans;
    //flag标记是否停靠,vis去重边 
    
    inline void add(int u,int v) 
    {
        cnt++;
        to[cnt]=v;
        nxt[cnt]=head[u];
        head[u]=cnt;
    }//邻接链表存边 
    
    int n,m;
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            memset(a,0,sizeof(a));
            memset(flag,0,sizeof(flag));
            int k;
            scanf("%d",&k);
            for(int j=1;j<=k;j++)
            {
                scanf("%d",&a[j]);
                flag[a[j]]=1;//标记 
            }
            for(int j=a[1]+1;j<=a[k];j++)
            {
                if(!flag[j])
                {
                    for(int p=1;p<=k;p++)
                    {
                        if(!vis[j][a[p]])
                        {
                            in[a[p]]++;
                            add(j,a[p]);
                            vis[j][a[p]]=1;
                        }
                    }
                }
            }
            
        }
        
        queue<int> q;
        for(int i=1;i<=n;i++)
        {
            if(!in[i]) q.push(i),dep[i]=1;
            //刚开始入度就为0的点深度为1 
        }
        while(!q.empty())
        {
            int top=q.front();
            q.pop();
            for(int e=head[top];e;e=nxt[e])
            {
                int v=to[e];
                dep[v]=max(dep[v],dep[top]+1);
                //这个不加max也可以,因为下面的ans已经取过max了
                //不过加上也没问题 
                ans=max(ans,dep[v]);//更新答案 
                in[to[e]]--;//入度-- 
                if(!in[to[e]]) q.push(to[e]);
            }
        }
        cout<<ans;
        
    }
    

    这是(ych)大神的代码(本蒟蒻表示还不会写)

  • 相关阅读:
    uvalive 3644 X-Plosives
    uva 11997 K Smallest Sums
    Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) D. Sorting the Coins
    Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) C. Classroom Watch
    Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) B. Divisiblity of Differences
    Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) A. Trip For Meal
    1004. 成绩排名 (20)
    1003. 我要通过!(20)
    1002. 写出这个数 (20)
    1001. 害死人不偿命的(3n+1)猜想 (15)
  • 原文地址:https://www.cnblogs.com/juruohqk/p/11056802.html
Copyright © 2011-2022 走看看