(Luogu) P1983 车站分级 (拓扑最长有效路径)

传送门

做这个题的第一步是先思考应该如何建图,停靠的站之间是没有严格的大于小于关系的,所以直接连边的话是不利于等级的划分的。所以再仔细考虑一下,我们应该是在起点到终点之间, 连接停靠的车站和没有停靠的车站,因为停靠的车站等级必定是严格大于未停靠车站的等级。根据这个严格的大小关系我们可以建有向图。可以从低的指向高的,也可以从高的指向低的,结果是一样的。

这里我建图是从低等级的指向高等级。然后跑一次拓扑最长路径,最长的路径就是需要的最少的标记级别,因为最长的都可以被标记出来,那那些比较短的必然也可以被标记出来。建图要用空间换时间不然会T

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=2e3+5;
int n,m;
vector<int> G[maxn];//邻接表
bool vis[maxn]; //访问标记
int degree[maxn],rankk[maxn];
//度 以i为终点的最长有效路径
bool added[maxn][maxn]; //标记是否被添加

int main() {
	scanf("%d%d",&n,&m);
	int s,tmp;
	int start,end;
	memset(added,true,sizeof(added));
	vector<int> unstop(maxn); //不停靠
	vector<int> stop(maxn); //停靠
	
	for(int t=0; t<m; ++t) {
		memset(vis,0,sizeof(vis));
		scanf("%d",&s);
		start=INF,end=-1;
		for(int i=0; i<s; ++i) {
			scanf("%d",&tmp);
			vis[tmp]=true;//停靠
			start=min(start,tmp);
			end=max(end,tmp);
		}
		
		unstop.clear();
		stop.clear();
		
		for(int i=start;i<=end;++i){
			if(!vis[i]){
				unstop.push_back(i);
			}
			if(vis[i]){
				stop.push_back(i);
			}
		} 
		
		for(int i=0;i<(int)stop.size();++i){ //停靠的向未停靠的连边
			for(int j=0;j<(int)unstop.size();++j){
				int be=stop[i],en=unstop[j];
				if(added[be][en]){ //是否已经被添加
					G[be].push_back(en);
					degree[en]++;
					added[be][en]=false;
				}
			}
		}
	}

	memset(vis,true,sizeof(vis));
	queue<int> q;
	for(int i=1; i<=n; ++i) {
		if(degree[i]==0) {
			q.push(i);
			vis[i]=false;
		}
	}
	int res=-1;
	while(!q.empty()) {
		int np=q.front();
		q.pop();
		for(int i=0; i<(int)G[np].size(); ++i) {
			int to=G[np][i];
			degree[to]--;
			rankk[to]=max(rankk[to],rankk[np]+1);//更新有效路径
			res=max(rankk[to],res); //更新最长有效路径
		}
		for(int i=1; i<=n; ++i) {
			if(vis[i]&&degree[i]==0) {
				q.push(i);
				vis[i]=false;
			}
		}
	}
	cout<<res+1<<endl;//初始化为0,所以+1
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值