CSP歷年複賽題-P1983 [NOIP2013 普及組] 車站分級

江城伍月發表於2024-06-03

原題連結:https://www.luogu.com.cn/problem/P1983

題意解讀:由於“如果這趟車次停靠了火車站,則始發站、終點站之間所有級別大於等於火車站的都必須停靠”。因此,在始發站和終點站之間,能停靠的車站都是級別較高的,沒有停靠的車站都是級別較低的,計算最少有多少個不同級別。

解題思路:

有若干車站可以是同一個級別,如未停靠的車站都可以設定同樣的低階別,停靠的車站根據相關關係也可以劃分不同的級別,可以透過建圖形成層級關係。

由於停靠的車站都是級別較高的,未停靠的車站都是級別較低的,所以對於起點、終點之間每一個未停靠的車站,可以建立一條指向停靠車站的邊

對樣例進行模擬

9 2 
4 1 3 5 6 
3 3 5 6

CSP歷年複賽題-P1983 [NOIP2013 普及組] 車站分級

圖中2、4是未停靠站,可以設定同樣的級別,1、3、5、6是停靠站,也可以設定同樣的級別,因此一共只需要2個級別。

在圖形結構中,2、4是拓撲排序的第一層,1、3、5、6是拓撲排序的第二層。

有了這個設想,在用另外一個樣例進行模擬,驗證是否正確

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

CSP歷年複賽題-P1983 [NOIP2013 普及組] 車站分級

上圖中,2、4、7、8是拓撲排序的第一層、3、6是拓撲排序的第二層,1、5、9是拓撲排序的第三層,因此一共只需要3個級別。

此方法驗證成立。

100分程式碼:

#include <bits/stdc++.h>
using namespace std;

const int N = 1005;

int g[N][N]; //鄰接矩陣,便於處理重邊的情況
int n, m, s, a[N], b[N]; //a[i]儲存所有停靠點 b[i]=1表示在第i站停靠
int in[N];
int depth[N], ans = 1; 

//透過拓撲排序,計算每個節點所在的深度,最大深度即不同的級別數
void bfs()
{
    queue<int> q;
    for(int i = 1; i <= n; i++)
    {
        if(in[i] == 0)
        {
            q.push(i);
            depth[i] = 1; //初始節點的深度
        } 
    }
    while (q.size())
    {
        int u = q.front(); q.pop();
        for(int v = 1; v <= n; v++)
        {
            if(g[u][v] == 1)
            {            
                if(--in[v] == 0)
                {
                    q.push(v);
                    depth[v] = depth[u] + 1;
                    ans = max(ans, depth[v]);
                } 
            }
        }
    }
    
}

int main()
{
    cin >> n >> m;
    while(m--)
    {
        cin >> s;
        memset(a, 0, sizeof(a)); 
        memset(b, 0, sizeof(b)); 
        for(int i = 1; i <= s; i++)
        {
            cin >> a[i]; //所有停靠站
            b[a[i]] = 1; //停靠站和非停靠站
        }
        for(int i = a[1]; i <= a[s]; i++) //遍歷起點到終點之間的站
        {
            if(b[i] == 0)//取未停靠站
            {
                for(int j = 1; j <= s; j++) //遍歷每一個停靠站a[j]
                {                
                    if(g[i][a[j]] == 0) in[a[j]]++; //記錄入度,去重邊
                    g[i][a[j]] = 1; //所有未停靠站和所有停靠站之間建立邊
                }
            }
        }
    }
    bfs();
    cout << ans;
    return 0;
}

相關文章