P1137 旅行计划

P1137 旅行计划

题目描述
小明要去一个国家旅游。这个国家有N个城市,编号为1至N,并且有M条道路连接着,小明准备从其中一个城市出发,并只往东走到城市i停止。

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

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

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

输出格式
N行,第ii行包含一个正整数,表示以第ii个城市为终点最多能游览多少个城市。

输入输出样例
输入

5 6
1 2
1 3
2 3
2 4
3 4
2 5

输出

1
2
3
4
3

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

思路:

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前(来源:百度百科)

通俗的说就是,一张有向无环图的拓扑序可以使得任意的起点u,它的一个终点v,在序列中的顺序是u在前v在后

仔细看DP部分,还记得DP需要满足什么原则吗?无后效性。如果不是在拓扑序后进行DP,会完全破坏无后效性。正是因为拓扑序u在前,v在后的性质,这才选择使用拓扑排序,毕竟它的代码实现很轻松,而且运行时间也不差。

#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
const int MAX=2147483647;
const int N=1e5+10;
struct node
{
	int u,v,next;
}edge[2*N];
int n,m,u,v,in[N],head,tail,que[N],hd[N],tot,f[N];
bool vis[N];
void add(int x,int y){edge[++tot]=(node){x,y,hd[x]};hd[x]=tot;}
void topsort()
{
	for(int i=1;i<=n;i++) if(!in[i]) que[++tail]=i,vis[i]=1;
	while(head<tail)
	{
		head++;
		int x=que[head];
		for(int i=hd[x];i;i=edge[i].next)
		{
			if(!vis[edge[i].v])
			{
				in[edge[i].v]--;
				if(!in[edge[i].v]) 
					que[++tail]=edge[i].v,vis[edge[i].v]=1;
			}
		}	
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++) scanf("%d%d",&u,&v),add(u,v),in[v]++;
	topsort();
	for(int i=1;i<=tail;i++)
	{
		int x=que[i];
		for(int j=hd[x];j;j=edge[j].next)
			f[edge[j].v]=max(f[edge[j].v],f[x]+1);
	}
	for(int i=1;i<=n;i++) printf("%d\n",f[i]+1);
	return 0;	
} 

你可能感兴趣的:(动态规划,拓扑排序)