1002 [NOIP2013]车站分级 拓扑排序 超级站点 给不好直接连边的点连边 给有层级关系但是没法直接标明的序列划分等级

链接:https://ac.nowcoder.com/acm/contest/26077/1002
来源:牛客网

题目描述

一条单向的铁路线上,依次有编号为1, 2, …, n 的n 个火车站。每个火车站都有一个级别,最低为1 级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站x,则始发站、终点站之间所有级别大于等于火车站x 的都必须停靠。(注意:起始站和终点站自然也算作事先已知需要停靠的站点)
例如,下表是5 趟车次的运行情况。其中,前4 趟车次均满足要求,而第5 趟车次由于停靠了3 号火车站(2 级)却未停靠途经的6 号火车站(亦为2 级)而不满足要求。


车站编号

1

 

2

 

3

 

4

 

5

 

6

 

7

 

8

 

9

车站级别

车次

3

 

1

 

2

 

1

 

3

 

2

 

1

 

1

 

3

1

 

 

 

 

 

 

2

 

 

 

 

 

 

 

 

 

 

3

4

 

 

 

 

 

 

5

 

 

 

 

 

现有 m 趟车次的运行情况(全部满足要求),试推算这 n 个火车站至少分为几个不同的级别。

 


输入描述:

第一行包含2个正整数n,m,用一个空格隔开。
第 i + 1 行(1 ≤ i ≤ m)中,首先是一个正整数 si(2 ≤ si ≤ n),表示第 i 趟车次有 si 个停靠站;接下来有si 个正整数,表示所有停靠站的编号,从小到大排列。
每两个数之间用一个空格隔开。输入保证所有的车次都满足要求。

 

输出描述:

输出只有一行,包含一个正整数,即n个火车站最少划分的级别数。
示例1

输入

复制
9 2
4 1 3 5 6
3 3 5 6

输出

复制
2
示例2

输入

复制
9 3
4 1 3 5 6
3 3 5 6
3 1 5 9

输出

复制
3

备注:

对于20%的数据,1 ≤n,m ≤10;
对于50%的数据,1 ≤n,m≤100;
对于100%的数据,1 ≤n,m ≤ 1000。

 

分析

N大小设错了,麻了,好多发搞了好久

题意大概是:当前车次行程中的所有站台的级别都比非站台的级别高。问这些站台总共有多少个级别

可以将所有非站台向站台连接一条长度为1的边,按照拓扑序给每个点标记距离更新距离

1 1 0 0 1 1 这样中间两个0就是1级,旁边的1就是二级

再加一段:1 1 1 0 1 1 这样这个0就是1级,原本是0变成1的位置就是2级,旁边的1变成了3级

内在的拓扑序是:0的所有边更新完了,然后1被放入队列,1的所有边被更新完了,旁边的1被放入队列

无法贪心的原因:因为有些车次可能长度不长:1 0 0 1 1 0。这样没办法通过0的数量或者1的数量来判断右边那个0到底是哪一级的(大概?)

反正拓扑序写的话绝对正确。

另外1e3的范围确实可以直接暴力写。

但是假如是1e5的范围,这样就不行了。这时候考虑

设一个特殊点:ver。表示车次

将所有当前车次所有站台都向非站台,可以将所有非站台连向车次,边长为1,再车次连向站台,边长为0。最后拓扑序就可以解决。

//-------------------------代码----------------------------

//#define int ll
const int N = 1000005,M = 2e3+10;
int n,m,d[M],e[N],ne[N],w[N],h[2010],idx;

void add(int a,int b,int c) {
    e[idx] = b,ne[idx] = h[a],w[idx] = c,d[b] ++ ,h[a] = idx ++ ;
}
bool vis[2010];
int ans[M],sum,dist[M];
void bfs() {
    queue<int> q;
    fo(i,1,n+m) {
        if(!d[i]) q.push(i);
    }
    while(q.size()) {
        int node = q.front();q.pop();ans[++sum] = node;
        fe(i,node) {
            int v = e[i];
            if(--d[v] == 0) q.push(v);
        }
    }
}

void solve()
{
    cin>>n>>m;
    ms(h,-1);ms(vis,0);
    fo(i,1,m) {
        ms(vis,0);
        int cnt;cin>>cnt;
        int start = n,end = 1;
        while(cnt -- ) {
            int stop;
            cin>>stop;
            start = min(start,stop);
            end = max(end,stop);
            vis[stop] = 1;
        }
        int ver = n + i;
        for(int j = start;j<=end;j++) {
            if(!vis[j]) add(j,ver,0);//非停靠点连接虚拟点
            else add(ver,j,1);//虚拟点连接停靠点
        }
    }
    bfs();
//     db(sum);
    for(int i = 1;i<=n;i++) dist[i] = 1;
    fo(i,1,sum) {
        int u = ans[i];
        for(int j = h[u];~j;j=ne[j]) {
            int v = e[j];
            int W = w[j];
            dist[v] = max(dist[v],dist[u] + W);
        }
    }
    int res = 0;
    fo(i,1,n) res = max(res,dist[i]);
    cout<<res<<endl;
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

posted @ 2022-08-17 18:16  er007  阅读(23)  评论(0编辑  收藏  举报