【2024.8.8】Traveller解题报告——拓扑排序

洛谷 P1983 [NOIP2013 普及组] 车站分级

解题思路

这道题是一道非常经典的建模为拓扑排序解决的实际问题。可以想到,如果不同的事物之间有从高到低的优先级关系,那么可以用一条从低优先级点连向高优先级点(或反过来)的边来表示这一种相对关系。根据这个思路,我们很容易想到如何去建图:低优先级的站点连一条边到高优先级的站点。

可以发现,当一列火车从 s s s t t t行驶的过程中,那些停靠的站点的优先级肯定要大于未停靠的站点。发现这一条规律以后其实这道题已经解决了。对于每一个列车运行的信息,都从所有未停靠的站点分别连一条边到所有停靠的站点。然后在形成的DAG上跑拓扑排序找到最长的路径即为答案。时间复杂度应为 O ( n m ) O(nm) O(nm)

Attention:注意到本题的边数量较多,考虑使用邻接矩阵存图(用邻接表可能会像我一样t到飞起

AC代码

实现拓扑排序找到最长路径的方法有很多种,例如bfs一层一层删点和边,但我的代码中使用的是记忆化搜索的方式。

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define pb push_back

#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define ff first
#define ss second
#define fori(x,y) for(int i=x;i<=(int)(y);++i)
#define forj(x,y) for(int j=x;j<=(int)(y);++j)
#define fork(x,y) for(int k=x;k<=(int)(y);++k)

#define debug(x) cout << #x << " = " << x << endl

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

ll MOD = 998244353;
ll qpow(ll a,ll p) {
   
   ll res=1; while(p) {
   
   if (p&1) {
   
   res=res*a%MOD;} a=a*a%MOD; p>>=1;} return res;}

const int N = 1e3+7;
int g[N][N];
int deg[N];

int n, q;
int dep[N];
int dfs(int u) {
   
   
    if (dep[u]) return dep[u];
    int res = 0;
    fori(1, n) if (g[u][i]) {
   
   
        res = max(res, dfs(i));
    }
    return (dep[u] = res+1);
}

bool is[N];
void solve() {
   
   
    cin >> n >> q;
    while (q--) {
   
   
        int m; cin >> m;
        fori(1, n) is[i] = false;
        int s, t;
        vector<int> vec;
        fori(1, m) {
   
   
            int x; cin >> x;
            if (i == 1) s = x;
            else if (i == m) t = x;
            is[x] = true;
            vec.push_back(x);
        }
        fori(s, t) if (!is[i]) {
   
   
            for (auto v: vec) {
   
   
                if (g[i][v]) continue;
                g[i][v] = 1;
                deg[v]++;
            }
        }
    }
    int ma = 1;
    fori(1, n) if (deg[i] == 0) ma = max(ma, dfs(i));
    cout << ma << endl;
}

signed main(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值