noip普及组2013 车站分级(luogu P1983)

本文介绍了一道洛谷编程题的解决方案,题目要求根据各车站的权值及车次路线信息,利用拓扑排序算法找出最大权值路径。文章详细解释了如何通过邻接矩阵存储边关系,避免重复计数,最终实现有效的拓扑排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:https://www.luogu.org/problem/show?pid=1983

题目大意:每个车站有一个权值,每一车次始发站与终点站之间如果有不停靠的点,那么它的权值一定比停靠的点的权值都要小。

处理完m条线路后,能够得到一系列的大小关系,于是就可以通过拓扑排序求出结果。

几个需要注意的地方:有的边可能已经被加过一次,所以最好用邻接矩阵存边,避免点的度数被重复加。

 

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std; 
void read(int &y)
{
    y=0;char x=getchar();
    while(x<'0'||x>'9') x=getchar();
    while(x>='0'&&x<='9')
    {
        y=y*10+x-'0';
        x=getchar();
     } 
}
int n,m,x,ans,top;
int p[1005],d[1005],l[1005];
int e[1005][1005],st[1005];
bool b[1005],vis[1005];
int main()
{
    read(n);read(m);
    for(int i=1;i<=m;i++)
    {
        memset(b,0,sizeof(b));
        read(x);
        for(int j=1;j<=x;j++)
        {
            read(p[j]);
            b[p[j]]=1;
        }
        for(int j=p[1];j<=p[x];j++)
        {
            if(b[j]!=0) continue;
            for(int k=1;k<=x;k++)
            {
                if(e[j][p[k]]!=0) continue;
                e[j][p[k]]=1;
                d[p[k]]++;
            }
        }
    }
    top=0;
    for(int i=1;i<=n;i++)
    {
        if(d[i]==0)
        {
            st[++top]=i;
            l[i]=1;
        }
    }
    for(int i=1;i<=top;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(e[st[i]][j]==0) continue;
            e[st[i]][j]=0;
            d[j]--;
            if(d[j]==0)
            {
                l[j]=l[st[i]]+1;
                ans=max(ans,l[j]);
                st[++top]=j;
            }
        }
    }
    printf("%d",ans);
    return 0;
} 

 

转载于:https://www.cnblogs.com/zeroform/p/7722002.html

``` #include<iostream> #include<cstdio> #include<cstring> #define ZYS 1005 using namespace std; int n,m,ans,st[ZYS],s,tuopu[ZYS][ZYS],de[ZYS],tt[ZYS],top; bool is[ZYS],bo[ZYS]; //用andyzys大佬的名字做数组范围 int main() { scanf("%d %d",&n,&m); for(int i=1;i<=m;i++) { memset(is,0,sizeof(is));//is表示是否是停靠站 scanf("%d",&s); for(int j=1;j<=s;j++) scanf("%d",&st[j]),is[st[j]]=true; for(int j=st[1];j<=st[s];j++) if(!is[j]) //枚举站点,若不是已停靠的就小于所有停靠站的等级 for(int k=1;k<=s;k++) //枚举已停靠站点 if(!tuopu[j][st[k]]) tuopu[j][st[k]]=1,de[st[k]]++;//tuopu[i][j]表示j>i的级别,如上 } do{ top=0; for(int i=1;i<=n;i++) if(de[i]==0&&!bo[i]) { tt[++top]=i,bo[i]=true;//开始将出度为0的点删掉 } for(int i=1;i<=top;i++) for(int j=1;j<=n;j++) if(tuopu[tt[i]][j]) tuopu[tt[i]][j]=0,de[j]--;//去边去点 ans++; } while(top); printf("%d",ans-1);//最后一次什么点都没有会多算一次(自行理解) return 0; }```# P1983 [NOIP 2013 普及组] 车站分级 ## 题目背景 NOIP2013 普及组 T4 ## 题目描述 一条单向的铁路线上,依次有编号为 $1, 2, …, n$ 的 $n $ 个火车站。每个火车站都有一个级别,最低为 $1$ 级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 $x$,则始发站、终点站之间所有级别大于等于火车站 $x$ 的都必须停靠。 注意:起始站和终点站自然也算作事先已知需要停靠的站点。 例如,下表是 $ 5 $ 趟车次的运行情况。其中,前 $ 4$ 趟车次均满足要求,而第 $5$ 趟车次由于停靠了 $3$ 号火车站($2$ 级)却未停靠途经的 $6$ 号火车站(亦为 $2$ 级)而不满足要求。 ![](https://cdn.luogu.com.cn/upload/pic/1238.png) 现有 $m$ 趟车次的运行情况(全部满足要求),试推算这 $ n$ 个火车站至少分为几个不同的级别。 ## 输入格式 第一行包含 $2$ 个正整数 $n, m$,用一个空格隔开。 第 $i + 1$ 行 $(1 ≤ i ≤ m)$ 中,首先是一个正整数 $s_i\ (2 ≤ s_i ≤ n)$,表示第 $ i$ 趟车次有 $s_i$ 个停靠站;接下来有 $ s_i$ 个正整数,表示所有停靠站的编号,从小到大排列。每两个数之间用一个空格隔开。输入保证所有的车次都满足要求。 ## 输出格式 一个正整数,即 $n$ 个火车站最少划分的级别数。 ## 输入输出样例 #1 ### 输入 #1 ``` 9 2 4 1 3 5 6 3 3 5 6 ``` ### 输出 #1 ``` 2 ``` ## 输入输出样例 #2 ### 输入 #2 ``` 9 3 4 1 3 5 6 3 3 5 6 3 1 5 9 ``` ### 输出 #2 ``` 3 ``` ## 说明/提示 对于 $ 20\%$ 的数据,$1 ≤ n, m ≤ 10$; 对于 $50\%$ 的数据,$1 ≤ n, m ≤ 100$; 对于 $100\%$ 的数据,$1 ≤ n, m ≤ 1000$。
03-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值