D151 拓扑排序 P1983 [NOIP 2013 普及组] 车站分级
D151 拓扑排序 P1983 [NOIP 2013 普及组] 车站分级_哔哩哔哩_bilibili
P1983 [NOIP 2013 普及组] 车站分级 - 洛谷
不停站的点的级别低,停站的点级别高,满足 m 趟车次的运行,问 n 个车站至少分为几个不同的级别。
思路
很容易想到从级别低的点向级别高的点连有向边,跑拓扑排序,计算最长路
最坏情况有 1000 趟车次,每趟有 1000 个站点,每趟有 500 个点停站,有 500 个点不停站
不停站的点都向停站的点连有向边,则有 $1000*500∗500=2.5\times 10^8$ 条边,超时
每趟车次建一个中间虚点,不停站的点向虚点连边权为 0 的边,虚点向停站的点连边权为 1 的边
最多有 $1000*(500+500)=10^6$ 条边,不超时
n 个点,m 趟车次,每趟车次建一个虚点,最多有 $n + m = 2000$ 个点
点分两类,这样的二分图,考虑建虚点,边的条数从 $N^2$ 降为 $2N$

相关板子:
// 拓扑排序 O(n+m) #include<bits/stdc++.h> using namespace std; const int N=2010; vector<pair<int,int>> e[N]; int n,m,a[N],vis[N]; int rd[N],d[N],ans=1; void topo(){ for(int i=1; i<=n; i++) d[i]=1; //最低级别为1 queue<int> q; for(int i=1; i<=n+m; i++) if(!rd[i]) q.push(i); while(!q.empty()){ int u=q.front(); q.pop(); for(auto [v,w]:e[u]){ d[v]=max(d[v],d[u]+w); //更新最长路 ans=max(ans,d[v]); if(--rd[v]==0) q.push(v); } } } int main(){ cin>>n>>m; //n个站点 m趟车次 for(int i=1,s; i<=m; i++){ memset(vis,0,sizeof vis); cin>>s; //停站个数 for(int j=1; j<=s; j++){ cin>>a[j]; vis[a[j]]=1; //停站标记 } int v=n+i; //建中间虚点 for(int j=a[1]; j<=a[s]; j++){ if(!vis[j]) e[j].emplace_back(v,0), rd[v]++; //不停站向虚点连边 else e[v].emplace_back(j,1), rd[j]++; //虚点向停站连边 } } topo(); cout<<ans; }
浙公网安备 33010602011771号