NOIP2013P4 车站分级 题解

(题目描述略)

本题为图论题。思路如下:

若一趟车次停靠了第i个节点和第j个节点,且第i个节点和第j个节点间无停靠点,则这趟车次所有停靠点级别必严格大于第i个节点和第j个节点中间所有的节点(不包括第i个节点和第j个节点)。换言之,所有已停靠的节点级别必严格大于起点站与终点站之间所有未停靠的节点(起点站与终点站算已停靠的节点)。

由此可以建有向图。当且仅当节点i级别严格大于节点j时,连一条有向边由i指向j(反之亦可),则将该问题转化为不含环的有向图中各边权值相等的最长路径问题。用拓扑排序即可解决。

代码如下:

#include"stdio.h"
#include"string.h"
bool array[2][1005],object[1005],repeat[1005][1005];
int a[1005],count[1005],map[1005][1005];
int main()
{
    freopen("level.in","r",stdin);
    freopen("level.out","w",stdout);
    memset(array,false,sizeof(array));//滚动数组,记录入度为0的点
    memset(count,0,sizeof(count));//记录每个点的入度
    memset(map,-1,sizeof(map));//邻接表存储图
    memset(object,true,sizeof(object));//记录该点是否已访问
    memset(repeat,true,sizeof(repeat));//记录该边是否重复
    int m,n,s;
    scanf("%d %d",&n,&m);
    for(int i=0;i<=n;i++)
        map[i][0]=1;//记录每个点的出度
    while(m--)
    {
        scanf("%d",&s);
        for(int i=0;i<s;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<s;i++)
            for(int j=a[i-1]+1;j<a[i];j++)
                for(int k=0;k<s;k++)
                    if(repeat[a[k]][j])
                        count[j]++,map[a[k]][map[a[k]][0]++]=j,repeat[a[k]][j]=false;
    }
    for(int i=1;i<=n;i++)
        if(count[i]==0)
            array[0][i]=true;
    for(m=n,s=0;m>0;s++)
    {
        for(int i=1;i<=n;i++)
            array[s&1^1][i]=false;
        for(int i=1;i<=n;i++)
            if(array[s&1][i]&&object[i])
            {
                m--;
                object[i]=false;
                for(int j=1;j<map[i][0];j++)
                {
                    count[map[i][j]]--;
                    if(count[map[i][j]]==0)
                        array[s&1^1][map[i][j]]=true;
                }
            }
    }
    printf("%d",s);
    return 0;
}

拓扑思路:每次删去当前状态下所有入度为0的点即其所连的边。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值