>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;
}