旅行计划【拓扑排序】【领接表】

>Description
这个国家有N个城市,编号为1至N,并且有M条道路连接着,从其中一个城市出发,并只往东走到城市i停止。

所以他需要选择最先到达的城市,并制定一条路线以城市i为终点,使得线路上除了第一个城市,每个城市都在路线前一个城市东面,并且满足这个前提下还希望游览的城市尽量多。

现在,你只知道每一条道路所连接的两个城市的相对位置关系,但并不知道所有城市具体的位置。现在对于所有的i,都需要你为小明制定一条路线,并求出以城市i为终点最多能够游览多少个城市。


>Input
第1行为两个正整数N,M。

接下来M行,每行两个正整数x,y,表示了有一条连接城市x与城市y的道路,保证了城市x在城市y西面。

>Output
N行,第i行包含一个正整数,表示以第i个城市为终点最多能游览多少个城市。


>Sample Input
5 6
1 2
1 3
2 3
2 4
3 4
2 5

>Sample Output
1
2
3
4
3

均选择从城市1出发可以得到以上答案。
对于20%的数据,N≤100;
对于60%的数据,N≤1000;
对于100%的数据,N≤100000,M≤200000。


>解题思路
拓扑排序:从入度为0的点开始,先把这一点加入数列,再把与这一点相连的线取消,然后从下一个入度为0的点开始,一直循环下去。

先把图拓扑排序一下,然后DP:f[i]表示以第i个城市为终点最多能游览多少个城市。
状态转移方程:f[i]=max(f[j]+1),f[j]表示与f[i]相连的点(j->i)


>代码

#include<iostream>
#include<cstdio>
using namespace std;
struct ooo
{
	int to,next;
}a[200005];
int n,m,x,y,tt,h[100005],f[100005],r[100005],st[100005],head,tail;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		a[++tt].to=y; a[tt].next=h[x]; h[x]=tt; //连接
		r[y]++; //入度
	}
	for(int i=1;i<=n;i++)
	 if(!r[i]) st[++tail]=i; //把入度为0的加入队列
	while(head<tail)
	{
		head++;
		for(int i=h[st[head]];i;i=a[i].next)
		{
            r[a[i].to]--; //取消这一条线(入度--)
		 	if(!r[a[i].to]) st[++tail]=a[i].to; //入度为0的话加入队列
		}
	}
	for(int i=1;i<=n;i++)
	 for(int j=h[st[i]];j;j=a[j].next)
	   f[a[j].to]=max(f[a[j].to],f[st[i]]+1); //DP
	for(int i=1;i<=n;i++)
	 printf("%d\n",f[i]+1); //还要加上开始的那一个点
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值