zoukankan      html  css  js  c++  java
  • P1983车站分级

    %%%rqy

    传送

    我们注意到题目中这段话:

    既然大于等于x的站都要停,那么不停的站的级别是不是都小于x?(这里讨论在始发站和终点站以内的站(注意这里是个坑))

    我们可以找出每趟车没停的站,向所有停了的站建一条边,表示没停的站的级别<停了的站的级别,同时记录所有的站的入度

    这样,一开始入度为0的站级别就是1。

    对于那些入度不为0的点来说,它们的级别就是所有指向它的点中,级别最大的那个点的级别+1

    for example

     因为每个级别为a车站x不一定只有级别为a-1的车站向x连边。

    那程序怎么实现呢?

    据大佬说要跑拓扑排序(%%%ych)

    简单的说:

    先将所有入度为0的点入队,遍历它们的每条出边,将所有到达的点的入度-1。如果有入度为0的点,就将其入队,并且它的级别为当前出队的点的级别+1。当队空时,拓扑排序结束。

    这样为什么能保证达到上图的效果呢?因为对于任意一点i来说,如果当前出队的点为j,若存在有连接i且级别比j大的点k,则k此时入度一定不为0(还没遍历j的出边时),就可以保证先算k的级别,再算i的级别了。

    复杂的说,走这里

    跑完拓扑排序,我们将所有点的级别sort一遍,找最大的,就是答案。

    小坑见代码

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    using namespace std;
    int aans,n,m,s[1005][1005],in[1005],head[1005],cnt,ans[1005];
    bool jb[1005][1005];//b[i][j]为i到j是否建过边(不建重边)
    queue <int> q;
    struct Edge{
        int to,next;
    }edge[10000005];//开大点(我也不知道最多有几条边,总之开小了会wa)
    void add(int fr,int to)//前向星存图
    {
        cnt++;
        edge[cnt].to=to;
        edge[cnt].next=head[fr];
        head[fr]=cnt;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
         {
          scanf("%d",&s[i][0]);
          bool rr[1005];int start,end;
          memset(rr,0,sizeof(rr));
          for(int j=1;j<=s[i][0];j++)
          {
            scanf("%d",&s[i][j]);
            rr[s[i][j]]=1;//标记每个点是否到达
            
          }start=s[i][1];end=s[i][s[i][0]];
           for(int j=start;j<=end;j++)//注意一定是讨论始发站和终点站以内的车站(见样例)
           {
               if(!rr[j])
                {  
                    for(int k=1;k<=s[i][0];k++)
                    {
                        if(!jb[j][s[i][k]])//不建重边
                    {add(j,s[i][k]);
                        in[s[i][k]]++;//建边的时候统计入度
                        jb[j][s[i][k]]=1;
                    }
                }
             }
           }    
         }
         for(int i=1;i<=n;i++)
          {
           if(!in[i])
           {
           q.push(i);
           ans[i]=1;
           }
          }
         while(!q.empty())//跑拓扑排序
         {
             int u=q.front();
             q.pop();
             for(int i=head[u];i;i=edge[i].next)
             {
                 in[edge[i].to]--;
                 if(in[edge[i].to]==0)
                 {
                  q.push(edge[i].to);
                  ans[edge[i].to]=ans[u]+1;
                 }
            }
         }
         sort(ans+1,ans+1+n);
         printf("%d",ans[n]);   
    }
  • 相关阅读:
    Linux常用命令大全
    C# 多线程、控制线程数提高循环输出效率
    【Redis笔记(四)】 Redis数据结构
    Redis 详解 (一) StackExchange.Redis Client
    C#中的线程(一)入门
    C#多线程
    StackExchange.Redis帮助类解决方案RedisRepository封装(散列Hash类型数据操作)
    【转】C#中使用Redis学习二 在.NET4.5中使用redis hash操作
    使用MongoDB.NET 2.2.4驱动版本对 Mongodb3.3数据库中GridFS增删改查
    .Net-Mongodb学习大全网址
  • 原文地址:https://www.cnblogs.com/lcez56jsy/p/11056969.html
Copyright © 2011-2022 走看看