[NOIP2013 普及组] 车站分级

原题链接

分析

这题还是比较好分析的

利用了,逆向思维。

当我们知道一个车次中所有能停靠的站后,通过题目可知,对停靠的每个点而言,没有停靠的一定不大于停靠点。

因此就好办了,我们知道每个车次之后,将所有的非停靠点和停靠点之间连一个边。

因为题目保证一定有解,则一定是无环的,因此直接跑一遍拓扑序即可。

两种存图方式

邻接矩阵

我们可以注意到,该题的边数最多有,5005001000,如果用链表直接存储的话,直接就会爆炸。

所有我的想法是,就存一个邻接矩阵嘛,问题也不大

Ac_code

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int stop[N],d[N],f[N];
bool st[N],g[N][N];
int n,m;

template < typename T >
inline void read(T &x)
{
    x = 0; bool f = 0; char ch = getchar();
    while(!isdigit(ch)){f ^= !(ch ^ 45);ch=getchar();}
    while(isdigit(ch)) x= (x<<1)+(x<<3)+(ch&15),ch=getchar();
    x = f ? -x : x;
}

void topsort()
{
    queue<int> q;
    for(int i=1;i<=n;i++)   
        if(!d[i])
        {
            q.push(i);
            f[i]=1;
            //cout<<i<<endl;
        }
    while(q.size())
    {
        auto t = q.front();
        q.pop();
        for(int i=1;i<=n;i++)
            if(g[t][i])
            {
                if(--d[i]==0) 
                    q.push(i);
                f[i]=max(f[i],f[t]+1);
            }
    }
}

int main()
{
    read(n),read(m);
    while(m--)
    {
        for(int i=1;i<=n;i++) st[i]=0;
        int t,mmin=n,mmax = 1,cnt=0;
        read(t);
        while(t--)
        {
            int x;
            read(x);
            stop[cnt++]=x;
            st[x]=1;
            mmin=min(mmin,x);
            mmax=max(mmax,x);
        }
        for(int i=0;i<cnt;i++)
            for(int j=mmin;j<=mmax;j++)
                if(!st[j]&&!g[j][stop[i]]){//这里卡了我半天,emmm,如果有重边,那要排除掉
                    g[j][stop[i]]=1,d[stop[i]]++;
                }
    }
    topsort();
    int ans = 0;
    for(int i=1;i<=n;i++) 
        ans=max(ans,f[i]);
    cout<<ans<<endl;
}

邻接表

这里如果直接用邻接表的话会直接炸掉。

所以我们,用了一个小技巧。

如果想在两个集合终点任意两点之间连一条边,那可以在两个集合中间,建一个虚拟点,将左边所有点,连接一个边权为0的边到虚拟点上,再从虚拟点连接边权为1的边到右边的集合中所有点。

这样边数,就从nm变为了n+m

#include<bits/stdc++.h>
using namespace std;
const int N = 2e3 + 10,M = 2e6 + 10;
int h[N],e[M],ne[M],w[M],idx;
int q[N],d[N];
bool st[N];
int dist[N];
int n,m;

void add(int a,int b,int c)
{
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++,d[b]++;
}

void topsort()
{
    int hh=0,tt=-1;
    for(int i=1;i<=n+m;i++)
        if(!d[i]) 
            q[++tt]=i;
    while(hh<=tt)
    {
        int t = q[hh++];
        for(int i = h[t];~i;i=ne[i])
        {
            int j = e[i];
            if(--d[j]==0)
                q[++tt]=j;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof h);
    for(int i=1;i<=m;i++)
    {
        memset(st, 0, sizeof st);
        int s;
        scanf("%d",&s);
        int start=n,end=1;
        while(s--)
        {
            int t;
            scanf("%d",&t);
            start=min(start,t);
            end=max(end,t);
            st[t]=1;
        }
        int ver = i + n;
        for(int j=start;j<=end;j++)
            if(st[j]) add(ver,j,1);
            else add(j,ver,0);
    }

    topsort();

    for(int i=1;i<=n;i++) dist[i]=1;
    for(int i=0;i<n+m;i++)
    {
        int j = q[i];
        for(int k = h[j];~k;k=ne[k])
            dist[e[k]]=max(dist[e[k]],dist[j]+w[k]);
    }

    int res = 0;
    for(int i=1;i<=n;i++) res=max(res,dist[i]);
    printf("%d\n",res);
    return 0;
}
posted @ 2021-11-19 14:40  艾特玖  阅读(353)  评论(0)    收藏  举报