456. 车站分级 拓扑排序 N 对 N 建边 虚拟节点优化 贪心

43 篇文章 1 订阅

题目在这里插入图片描述

TP

题解思路

建立有向边来表示差分约束。

会大一级就建1边 。站点之间不建边。使得答案最小。(贪心)

这样图的最长路就是答案了。

而拓扑序利用边权来更新最大值,就可以满足答案是最长路(根据拓扑排序的定义理解)。

再这样再跑一遍拓扑序来得出答案。

这样车站之间建边可能会变成nn , y总用虚拟点优化使得只需2n条边即可。
在这里插入图片描述

AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
using namespace std;

const  int  INF =  0x3f3f3f3f;


struct node
{
    int q , w ;
};
vector <node> head[2010] ;
int a[2010] ;
int vis[2010] ;

int main ()
{
    ios::sync_with_stdio(false);cin.tie(0);
    int n , m ;
    cin >> n >> m ;
    int cnt = n + 1 ;
    for ( int i = 1 ; i <= m ; i++ )
    {
        int t ;
        cin >> t ;
        int fx = 1 ;
        vector <int> mi ;
        vector <int> mx ;
        for (int j = 1 ; j <= t ; j++ )
        {
            int t1 ;
            cin >> t1 ;
            mx.push_back(t1) ;
            if ( j == 1 )
            {
                fx = t1 ;
                continue ;
            }
            if ( t1 > fx )
            {
                fx ++ ;
                while ( fx < t1 )
                {
                    mi.push_back(fx);
                   // cout << fx << "\n" ;
                    fx ++ ;
                }
            }
        }
        if (  mi.size() )
        {
            for ( auto j : mi )
            {
                head[j].push_back({cnt,0}) ;
                a[cnt]++;
                //cout << j << " " << cnt << "\n" ;
            }
            for ( auto k : mx )
            {
                head[cnt].push_back({k,1}) ;
                a[k]++;
            }
            cnt++ ;
        }
    }

    queue <int> q ;
    for ( int i = 1 ; i < cnt ; i++ )
    {
        vis[i] = 1  ;
        if ( a[i] == 0 )
        {
            vis[i] =  1 ;
            q.push(i) ;
        }
    }
    vector <int>  ts ;
    while ( !q.empty() )
    {
        int tmp = q.front() ;
        ts.push_back(tmp) ;
        q.pop() ;
        for ( int i = 0 ; i < head[tmp].size() ; i++ )
        {
            int p = head[tmp][i].q ;
            a[p] -- ;
            if ( a[p] == 0 )
            {
                q.push(p) ;
            }
        }
    }
    int ans = 1 ;
    for ( int i = 0 ; i < ts.size() ; i++ )
    {
        for ( int j = 0 ; j < head[ts[i]].size() ; j++ )
        {
            vis[ head[ts[i]][j].q ] =  max( vis[ head[ts[i]][j].q ]   , vis[ts[i]] + head[ts[i]][j].w  ) ;
         //   ans = max( vis[ head[i][j].q ]  , ans );
        }
    }
    for ( int i = 1 ; i <= n ; i++ )
        ans = max( ans , vis[i] ) ;
    cout << ans << "\n" ;

    return 0 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值