<h1>题目</h1>
<h2>题目描述</h2>
小明要去一个国家旅游。这个国家有$ N $个城市,编号为 $ 1 $至$ N $,并且有$ M $条道路连接着,小明准备从其中一个城市出发,并只往东走到城市$ i $停止。
所以他就需要选择最先到达的城市,并制定一条路线以城市$ i $为终点,使得线路上除了第一个城市,每个城市都在路线前一个城市东面,并且满足这个前提下还希望游览的城市尽量多。
现在,你只知道每一条道路所连接的两个城市的相对位置关系,但并不知道所有城市具体的位置。现在对于所有的$ i $,都需要你为小明制定一条路线,并求出以城市$ i $为终点最多能够游览多少个城市。
<h2>输入输出格式</h2>
<h3>输入格式:</h3>
第$ 1$行为两个正整数$ N,M $。
接下来$ M $行,每行两个正整数$ x,y$,表示了有一条连接城市$ x $与城市$ y $的道路,保证了城市$ x $在城市$ y $西面。
<h3>输出格式:</h3>
$ N $行,第$ i $行包含一个正整数,表示以第$ i $个城市为终点最多能游览多少个城市。
<h2>输入输出样例</h2>
<h3>输入样例#1:</h3>
[code lang=text]
5 6
1 2
1 3
2 3
2 4
3 4
2 5
[/code]
<h3>输出样例#1</h3>
[code lang=text]
1
2
3
4
3
[/code]
<h2>说明</h2>
均选择从城市 $ 1 $ 出发可以得到以上答案。
对于 $ 20\% $ 的数据, $ 1 \le N\le 100$ ;
对于 $ 60\% $ 的数据,$ 1\le N\le 1000 $ ;
对于 $100\%$ 的数据, $ 1 \le N \le 100000,1\le M\le 200000 $ 。
<h1>解题报告</h1>
这一题是练习拓扑排序的上手简单题目。
首先,这一题可以用DP
来做。但是一个不经过拓扑排序的图有后效性。
经过拓扑排序之后按照拓扑序来进行DP
即可。
至于如何动态规划:我们考虑拓扑排序完后,只能从东向西走,那么不妨设$ dp_u $表示以节点u为终点,能经过的最多的城市。这就是一个简单的线性dp,状态转移方程为:
$$ dp_u = Max{dp_v}(u和v连通)$$
详情见代码。
<h1>代码</h1>
#include <iostream> #include <cstring> #include <cstdio> #include <queue> #define add(u,v) node[u].firstEdge = New(&node[u],&node[v]) const int MAXN = 100000 + 5; const int MAXM = 200000 + 5; struct Node; struct Edge; int N,M,cnt; Node* ts[MAXN]; struct Node{ int ru,dp; bool used; Edge *firstEdge; }node[MAXN]; struct Edge{ Node s,t; Edge *next; }pool[MAXM],*frog = pool; Edge New(Node s,Node *t){ Edge *ret = ++frog; ret->s = s;ret->t = t; ret->next = s->firstEdge; return ret; } //内存池 inline void topsort(){ std::queue<Node *> q; for(int i = 1;i <= N;i++) if(!node[i].ru){ q.push(&node[i]); ts[++cnt] = &node[i]; } while(!q.empty()){ Node *v = q.front();q.pop(); for(Edge *e = v->firstEdge;e;e = e->next){ if(!--e->t->ru){ q.push(e->t); ts[++cnt] = e->t; } } } } int main(){ scanf("%d%d",&N,&M); for(int u,v,i = 1;i <= M;i++){ scanf("%d%d",&u,&v); add(u,v); node[v].ru++; } topsort(); for(int i = 1;i <= N;i++) node[i].dp = 1; for(int i = 1;i <= N;i++){ Node *v = ts[i]; for(Edge *e = v->firstEdge;e;e = e->next){ e->t->dp = std::max(e->t->dp,v->dp + 1); } } for(int i = 1;i <= N;i++) printf("%dn",node[i].dp); return 0; }