P1983 [NOIP2013 普及组] 车站分级

原题链接
考察:拓扑排序
思路:
  等级低与等级高之间建立边.比如区间[1,6]之间停靠了(1,3,5,6).那么在(1,3,5,6)与(2,4)之间两两间加一条边.最后拓扑排序即可.
  但是这样会TLE.时间复杂度O(109),空间复杂度极限O(500*500*1000).需要进一步优化.image

  但是注意初始化等级时,虚点不能初始化为1,因为不一定有入度.

Code

#include <iostream>
#include <cstring>
#include <set>
using namespace std;
const int N = 1010;
int h[N<<1],idx,n,m,d[N<<1],q[N<<1],level[N<<1],p;
set<int> s;
struct Road{
    int fr,to,ne,w;
}road[N*N<<2];
void add(int a,int b,int w)
{
    road[idx].w = w,road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
}
void topsort()
{
    int hh=0,tt=-1;
    for(int i=1;i<=p;i++) if(!d[i]) q[++tt] = i;
    while(hh<=tt)
    {
        int u = q[hh++];
        for(int i=h[u];~i;i=road[i].ne)
        {
            int v = road[i].to;
            if(--d[v]==0) q[++tt] = v;
        }
    }
}
void solve()
{
    int res = 0;
    for(int i=1;i<=n;i++) level[i] = 1;//存在没有入度的虚拟点
    for(int i=0;i<p;i++)
    {
        int u = q[i];
        res = max(res,level[u]);
        //if(level[u]==6) printf("%d\n",u);
        for(int j=h[u];~j;j=road[j].ne)
        {
            int v = road[j].to;
            level[v] = max(level[v],level[u]+road[j].w);
       //     printf("%d %d %d %d\n",road[j].fr,road[j].to,road[j].w,level[v]);
        }
    }
    printf("%d\n",res);
}
int main()
{
    memset(h,-1,sizeof h);
    scanf("%d%d",&n,&m);
    p = n+1;
    while(m--)
    {
        int sz,l=3*n,r=0;
        scanf("%d",&sz);
        s.clear();
        for(int i=1;i<=sz;i++)
        {
            int x; scanf("%d",&x);
            s.insert(x);
            add(p,x,1);
            l = min(x,l);
            r = max(r,x);
            d[x]++;
        }
        for(int i=l+1;i<r;i++)
          if(!s.count(i)) 
		    add(i,p,0),d[p]++;
        p++;
    }
    topsort();
    solve();
    return 0;
}
posted @ 2021-06-06 08:57  acmloser  阅读(129)  评论(0编辑  收藏  举报