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