题目:车站分级

题意转化:对于一班车,从起点到终点的所有站中,把非经停站向所有经停站连一条长度是1的边,表示前者的等级要严格小于后者的等级

问题:爆空间

解决方法:考虑到这种一群点向另一群点两两连边,可以优化为一群点先向一个虚拟点连一条长度为0边,再从这个虚拟点向另一边连一条长度是1的边,可以把空间从O(N3)优化到O(N2)

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2010,M=2e6+10;
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int c)  
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
int n,m;
int d[N];
int q[N];
int hh,tt=-1;
int dist[N];
bool st[N];
vector<int>tmp;
int main(){
    cin>>n>>m;
    memset(h, -1, sizeof h);
    int vir=1001;
    for(int i=1;i<=m;i++){
        memset(st, 0, sizeof st);
        int tm;
        cin>>tm;
        int start,end;
        for(int j=1;j<=tm;j++){
            int c;
            cin>>c;
            if(j==1)start=c;
            if(j==tm)end=c;
            st[c]=true;
        }
        tmp.clear();
        for(int i=start;i<=end;i++)
            if(!st[i])tmp.push_back(i);
        if(tmp.empty())continue;
        for(int i=start;i<=end;i++)
            if(st[i])add(vir,i,1),d[i]++;
            else add(i,vir,0),d[vir]++;
        vir++;
    }
    
    for(int i=1;i<=n;i++)
        if(!d[i])q[++tt]=i,dist[i]=1;
    while(hh<=tt){
        int t=q[hh++];
        for(int i= h[t];~i;i=ne[i]){
            int j=e[i];
            d[j]--;
            if(!d[j])q[++tt]=j;
            dist[j]=max(dist[j],dist[t]+w[i]);
        }
    }
    
    int ma=-1;
    for(int i=1;i<=n;i++)ma=max(ma,dist[i]);
    cout<<ma<<endl;
}