拓扑排序 建图 模板题 车站分级

超水
题目在上面,这个是一个经典的拓扑排序和建图的模板,大家可以试试水,首先我们要理解题目,假设有一串编号1 3 5,这个就是1,5分别是起点和终点,而且只停靠3,所以2,4这两个车站必须要小于,1、3、5这三个,而其中三个关系是:1≤3≤5,本着贪心的原则:能等则等所以我们令他们相等,那么我们可以这样建图,如果2<3的话(注意没有等于),那么我们就添加一条从2通向3的边,这样我们只需要计算生成的这个图最大有几层就好了,原因是:如果2->3->5的话意味着2<3<5,所以要三级才可以,这一块是重点,没有理解的可以留言。
那么我们只需要计算图最大有几层就好了,我们可以用拓扑排序,然后DP计算,我们定义d[i]表示到i点的最大层数是多少,知道拓扑排序的都知道这个按着拓扑排序DP就好了。
下面上代码:

#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
queue <int> q;//拓扑排序用的数组 
int map[1010][1010],num[1010],d[1010],n,v[1010],stan[1010]; 
int read()
{
    char ch;
    while(ch=getchar(),ch<'0' || ch>'9');
    int num=ch-'0';
    while(ch=getchar(),ch>='0' && ch<='9')
        num=num*10+ch-'0';
    return num;
}
void write(int n){
    if(n==0) return;
    write(n/10);
    putchar(n%10+'0');
}
int main()
{
    int m,ans=0,x;
    n=read();
    m=read();
    for(int i=1;i<=m;i++)//读入数据 
    {
        int x,s0=0,s1;
        x=read();
        memset(v,0,sizeof(v));
        for(int j=1;j<=x;j++)
        {
            stan[j]=read();//快读一下 
            v[stan[j]]=1;
        }
        for(int j=stan[1]+1;j<stan[x];j++)
        {
            if(v[j]==1)
                continue;
            for(int k=1;k<=x;k++)
            {
                map[j][stan[k]]=1;//寻找没有停靠的点,在枚举所有有停靠的点见一条从前者到后者的边 
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
            if(map[i][j]==1)
                num[j]++;//拓扑排序统计一下每个点的入度 
    }
    for(int i=1;i<=n;i++)//入度为0的入队计算 
    {
        if(num[i]!=0)
            continue;
        d[i]=1;
        q.push(i);
    }
    while(!q.empty())//循环拓扑排序 
    {
        x=q.front();//取队头 
        q.pop();
        for(int i=1;i<=n;i++)//枚举所有与它相邻的点 
        {
            if(map[x][i]==1)//相邻 
            {
                num[i]--;//去边 
                d[i]=max(d[x]+1,d[i]);//DP 
                if(d[i]>ans)//找答案 
                    ans=d[i];
                if(num[i]==0)
                    q.push(i);
            }
        }
    }
    write(ans);//快输一波 
    return 0;
}

希望大家可以AC,有不懂得可以留言,有错误也欢迎指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值