AcWing 456. 車站分級
阿新 • • 發佈:2021-08-25
原題連結AcWing 456. 車站分級
抽象出題意,停靠過的車站的等級一定嚴格大於為停靠過的車站的等級,且不存在環,例如車站\(A\)等級大於車站\(B\),則\(A >= B + 1\),不妨從\(B\)向\(A\)連一條邊,表示等級關係,題目要求車站的最小等級中最大是多少,即求最長路,那這就是一個差分約束系統。
而對於差分約束系統:
如果邊權有正有負:則使用\(spfa\)
如果邊權非負,那麼可以使用\(tarjan\)縮點+遞推,\(拓撲排序 + 遞推\)的方式求最長路或者最短路。
同時,對於本題,把未停靠的站點和停靠的分成兩個集合,那麼需要連邊最壞情況下是要\(n^2\),考慮最壞情況下,一共有\(1000\)
// Problem: 車站分級 // Contest: AcWing // URL: https://www.acwing.com/problem/content/458/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> using namespace std; const int N = 2010, M = 1E6 + 10; int h[N], e[M], ne[M], w[M], idx; int n, m; int d[N]; int dist[N]; int seq[N], cnt; bool st[N]; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++; d[b]++; } void topsort() { queue<int> q; for (int i = 1; i <= n + m; i++) { if (!d[i]) q.push(i); } while (q.size()) { int t = q.front(); q.pop(); seq[cnt++] = t; for (int i = h[t]; ~i; i = ne[i]) { int j = e[i]; if (--d[j] == 0) q.push(j); } } } int main() { scanf("%d%d", &n, &m); memset(h, -1, sizeof h); for (int i = 1; i <= m; i++) { int cnt; scanf("%d", &cnt); memset(st, 0, sizeof st); int start = n, end = 1; while (cnt--) { int k; scanf("%d", &k); start = min(start, k); end = max(end, k); st[k] = true; } int vir = n + i; for (int j = start; j <= end; j++) { if (!st[j]) add(j, vir, 0); else add(vir, j, 1); } } topsort(); for (int j = 1; j <= n; j++) dist[j] = 1; for (int j = 0; j < n + m; j++) { int var = seq[j]; for (int k = h[var]; ~k; k = ne[k]) { dist[e[k]] = max(dist[e[k]], dist[var] + w[k]); } } int res = 0; for (int i = 1; i <= n; i++) res = max(res, dist[i]); printf("%d\n", res); return 0; }