洛谷P1983車站分級

洛谷\(P1983\)車站分級(拓撲排序)

目錄

  • 題目描述

  • 題目分析

  • 思路分析

  • 代碼實現


題目描述

題目在洛谷\(P1983\)html

題目:c++

一條單向的鐵路線上,依次有編號爲 \(1, 2, …, n1,2,…,n\)\(n\)個火車站。每一個火車站都有一個級別,最低爲 11 級。現有若干趟車次在這條線路上行駛,每一趟都知足以下要求:若是這趟車次停靠了火車站 \(x\),則始發站、終點站之間全部級別大於等於火車站\(x\) 的都必須停靠。(注意:起始站和終點站天然也算做事先已知須要停靠的站點)spa

例如,下表是\(5\)趟車次的運行狀況。其中,前\(4\)趟車次均知足要求,而第\(5\)趟車次因爲停靠了\(3\)號火車站(\(2\)級)卻未停靠途經的\(6\)號火車站(亦爲\(2\)級)而不知足要求。imgcode

現有\(m\) 趟車次的運行狀況(所有知足要求),試推算這\(n\)個火車站至少分爲幾個不一樣的級別。htm

輸入輸出格式:blog

輸入:第一行包含\(2\)個正整數\(n, m\),用一個空格隔開。排序

\(i + 1\)\((1 ≤ i ≤ m)\)中,首先是一個正整數\(s_i(2 ≤ s_i ≤ n)\),表示第\(i\) 趟車次有\(s_i\) 個停靠站;接下來有\(s_i\)個正整數,表示全部停靠站的編號,從小到大排列。每兩個數之間用一個空格隔開。輸入保證全部的車次都知足要求。get

輸出:一個正整數,即\(n\)個火車站最少劃分的級別數。it


題目分析

​ 剛剛看到這道題時,我並無讀懂題,以爲是要用一個\(dp\)或者搜索什麼的(也有多是我搜索題作多了class

看到題目,咱們知道,假設一個車次從\(x\)車站駛向\(y\)車站,\(c_i\)表示第\(i\)個車站的車站等級。那麼中間的\(c_i(x \leq i \leq y)\)必定知足\(c_i\leq 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\)大神的代碼(本蒟蒻表示還不會寫)

相關文章
相關標籤/搜索